On Fri, 15 Apr 2011 11:01:55 +0400 Pavel Shilovsky <piastry@xxxxxxxxxxx> wrote: > Now we point superblock to a server share root and set a root dentry > appropriately. This let us share superblock between mounts like > //server/sharename/foo/bar and //server/sharename/foo further. > > Signed-off-by: Pavel Shilovsky <piastry@xxxxxxxxxxx> > --- > fs/cifs/cifs_fs_sb.h | 2 - > fs/cifs/cifsfs.c | 95 +++++++++++++++++++++++++++++++++++- > fs/cifs/cifsglob.h | 76 +++++++++++++++++++++++++++++ > fs/cifs/cifsproto.h | 5 +- > fs/cifs/connect.c | 129 ++------------------------------------------------ > fs/cifs/dir.c | 7 +-- > fs/cifs/inode.c | 15 +++--- > 7 files changed, 186 insertions(+), 143 deletions(-) > > diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h > index adecd36..a18ba37 100644 > --- a/fs/cifs/cifs_fs_sb.h > +++ b/fs/cifs/cifs_fs_sb.h > @@ -58,8 +58,6 @@ struct cifs_sb_info { > mode_t mnt_file_mode; > mode_t mnt_dir_mode; > unsigned int mnt_cifs_flags; > - int prepathlen; > - char *prepath; /* relative path under the share to mount to */ > char *mountdata; /* options received at mount time or via DFS refs */ > struct backing_dev_info bdi; > struct delayed_work prune_tlinks; > diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c > index 3227db6..44394c8 100644 > --- a/fs/cifs/cifsfs.c > +++ b/fs/cifs/cifsfs.c > @@ -434,8 +434,6 @@ cifs_show_options(struct seq_file *s, struct vfsmount *m) > seq_printf(s, ",nocase"); > if (tcon->retry) > seq_printf(s, ",hard"); > - if (cifs_sb->prepath) > - seq_printf(s, ",prepath=%s", cifs_sb->prepath); > if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) > seq_printf(s, ",posixpaths"); > if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) > @@ -549,6 +547,92 @@ static const struct super_operations cifs_super_ops = { > #endif > }; > > +/* > + * Get root dentry from superblock according to prefix path mount option. > + * Return dentry with refcount + 1 on success and NULL otherwise. > + */ > +static struct dentry * > +cifs_get_root(struct smb_vol *vol, struct super_block *sb) > +{ > + int xid, rc; > + struct inode *inode; > + struct qstr name; > + struct dentry *dparent = NULL, *dchild = NULL; > + struct cifs_sb_info *cifs_sb = CIFS_SB(sb); > + unsigned int i, full_len, len; > + char *full_path = NULL, *pstart; > + char sep; > + > + full_path = cifs_build_path_to_root(vol, cifs_sb, > + cifs_sb_master_tcon(cifs_sb)); > + if (full_path == NULL) > + return NULL; > + > + cFYI(1, "Get root dentry for %s", full_path); > + > + xid = GetXid(); > + sep = CIFS_DIR_SEP(cifs_sb); > + dparent = dget(sb->s_root); > + full_len = strlen(full_path); > + full_path[full_len] = sep; > + pstart = full_path + 1; > + > + for (i = 1, len = 0; i <= full_len; i++) { > + if (full_path[i] != sep || !len) { > + len++; > + continue; > + } > + > + full_path[i] = 0; > + cFYI(1, "get dentry for %s", pstart); > + > + name.name = pstart; > + name.len = len; > + name.hash = full_name_hash(pstart, len); > + dchild = d_lookup(dparent, &name); > + if (dchild == NULL) { > + cFYI(1, "not exists"); > + dchild = d_alloc(dparent, &name); > + if (dchild == NULL) { > + dput(dparent); > + dparent = NULL; > + goto out; > + } > + } > + > + cFYI(1, "get inode"); > + if (dchild->d_inode == NULL) { > + cFYI(1, "not exists"); > + inode = NULL; > + if (cifs_sb_master_tcon(CIFS_SB(sb))->unix_ext) > + rc = cifs_get_inode_info_unix(&inode, full_path, > + sb, xid); > + else > + rc = cifs_get_inode_info(&inode, full_path, > + NULL, sb, xid, NULL); > + if (rc) { > + dput(dchild); > + dput(dparent); > + dparent = NULL; > + goto out; > + } > + d_add(dchild, inode); ^^^^^^ Is this racy? Could another dentry have been added between the time that you did the initial lookup and here? I think there are functions that guard against that possibility. d_materialise_unique maybe? > + } > + cFYI(1, "parent %p, child %p", dparent, dchild); > + > + dput(dparent); > + dparent = dchild; > + len = 0; > + pstart = full_path + i + 1; > + full_path[i] = sep; > + } > +out: > + _FreeXid(xid); > + full_path[full_len] = 0; ^^^ that's unnecessary, you free this just afterward. > + kfree(full_path); > + return dparent; > +} > + > static struct dentry * > cifs_do_mount(struct file_system_type *fs_type, > int flags, const char *dev_name, void *data) > @@ -603,7 +687,12 @@ cifs_do_mount(struct file_system_type *fs_type, > > sb->s_flags |= MS_ACTIVE; > > - root = dget(sb->s_root); > + root = cifs_get_root(volume_info, sb); > + if (root == NULL) { > + kfree(copied_data); > + goto err_out; > + } > + cFYI(1, "dentry root is: %p", root); > out: > cifs_cleanup_volume_info(&volume_info); > return root; [...] > @@ -887,16 +887,17 @@ struct inode *cifs_root_iget(struct super_block *sb) > char *full_path; > struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); > > - full_path = cifs_build_path_to_root(cifs_sb, tcon); > + full_path = kmalloc(1, GFP_KERNEL); > if (full_path == NULL) > return ERR_PTR(-ENOMEM); > + full_path[0] = 0; > Don't kmalloc 1 byte, just pass "" or do it on the stack instead. > xid = GetXid(); > if (tcon->unix_ext) > rc = cifs_get_inode_info_unix(&inode, full_path, sb, xid); > else > - rc = cifs_get_inode_info(&inode, full_path, NULL, sb, > - xid, NULL); > + rc = cifs_get_inode_info(&inode, full_path, NULL, sb, xid, > + NULL); > > if (!inode) { > inode = ERR_PTR(rc); -- Jeff Layton <jlayton@xxxxxxxxxx> -- To unsubscribe from this list: send the line "unsubscribe linux-cifs" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html