Navigation Menu

Skip to content

Commit

Permalink
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel…
Browse files Browse the repository at this point in the history
…/git/viro/vfs-2.6

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6:
  cifs: propagate errors from cifs_get_root() to mount(2)
  cifs: tidy cifs_do_mount() up a bit
  cifs: more breakage on mount failures
  cifs: close sget() races
  cifs: pull freeing mountdata/dropping nls/freeing cifs_sb into cifs_umount()
  cifs: move cifs_umount() call into ->kill_sb()
  cifs: pull cifs_mount() call up
  sanitize cifs_umount() prototype
  cifs: initialize ->tlink_tree in cifs_setup_cifs_sb()
  cifs: allocate mountdata earlier
  cifs: leak on mount if we share superblock
  cifs: don't pass superblock to cifs_mount()
  cifs: don't leak nls on mount failure
  cifs: double free on mount failure
  take bdi setup/destruction into cifs_mount/cifs_umount

Acked-by: Steve French <smfrench@gmail.com>
  • Loading branch information
torvalds committed Jun 27, 2011
2 parents 8abf558 + 9403c9c commit 804a007
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 116 deletions.
1 change: 1 addition & 0 deletions fs/cifs/cifs_fs_sb.h
Expand Up @@ -42,6 +42,7 @@
#define CIFS_MOUNT_MULTIUSER 0x20000 /* multiuser mount */
#define CIFS_MOUNT_STRICT_IO 0x40000 /* strict cache mode */
#define CIFS_MOUNT_RWPIDFORWARD 0x80000 /* use pid forwarding for rw */
#define CIFS_MOUNT_POSIXACL 0x100000 /* mirror of MS_POSIXACL in mnt_cifs_flags */

struct cifs_sb_info {
struct rb_root tlink_tree;
Expand Down
156 changes: 65 additions & 91 deletions fs/cifs/cifsfs.c
Expand Up @@ -104,31 +104,24 @@ cifs_sb_deactive(struct super_block *sb)
}

static int
cifs_read_super(struct super_block *sb, struct smb_vol *volume_info,
const char *devname, int silent)
cifs_read_super(struct super_block *sb)
{
struct inode *inode;
struct cifs_sb_info *cifs_sb;
int rc = 0;

cifs_sb = CIFS_SB(sb);

spin_lock_init(&cifs_sb->tlink_tree_lock);
cifs_sb->tlink_tree = RB_ROOT;
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIXACL)
sb->s_flags |= MS_POSIXACL;

rc = bdi_setup_and_register(&cifs_sb->bdi, "cifs", BDI_CAP_MAP_COPY);
if (rc)
return rc;

cifs_sb->bdi.ra_pages = default_backing_dev_info.ra_pages;
if (cifs_sb_master_tcon(cifs_sb)->ses->capabilities & CAP_LARGE_FILES)
sb->s_maxbytes = MAX_LFS_FILESIZE;
else
sb->s_maxbytes = MAX_NON_LFS;

rc = cifs_mount(sb, cifs_sb, volume_info, devname);

if (rc) {
if (!silent)
cERROR(1, "cifs_mount failed w/return code = %d", rc);
goto out_mount_failed;
}
/* BB FIXME fix time_gran to be larger for LANMAN sessions */
sb->s_time_gran = 100;

sb->s_magic = CIFS_MAGIC_NUMBER;
sb->s_op = &cifs_super_ops;
Expand Down Expand Up @@ -170,37 +163,14 @@ cifs_read_super(struct super_block *sb, struct smb_vol *volume_info,
if (inode)
iput(inode);

cifs_umount(sb, cifs_sb);

out_mount_failed:
bdi_destroy(&cifs_sb->bdi);
return rc;
}

static void
cifs_put_super(struct super_block *sb)
static void cifs_kill_sb(struct super_block *sb)
{
int rc = 0;
struct cifs_sb_info *cifs_sb;

cFYI(1, "In cifs_put_super");
cifs_sb = CIFS_SB(sb);
if (cifs_sb == NULL) {
cFYI(1, "Empty cifs superblock info passed to unmount");
return;
}

rc = cifs_umount(sb, cifs_sb);
if (rc)
cERROR(1, "cifs_umount failed with return code %d", rc);
if (cifs_sb->mountdata) {
kfree(cifs_sb->mountdata);
cifs_sb->mountdata = NULL;
}

unload_nls(cifs_sb->local_nls);
bdi_destroy(&cifs_sb->bdi);
kfree(cifs_sb);
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
kill_anon_super(sb);
cifs_umount(cifs_sb);
}

static int
Expand Down Expand Up @@ -548,7 +518,6 @@ static int cifs_drop_inode(struct inode *inode)
}

static const struct super_operations cifs_super_ops = {
.put_super = cifs_put_super,
.statfs = cifs_statfs,
.alloc_inode = cifs_alloc_inode,
.destroy_inode = cifs_destroy_inode,
Expand Down Expand Up @@ -585,7 +554,7 @@ cifs_get_root(struct smb_vol *vol, struct super_block *sb)
full_path = cifs_build_path_to_root(vol, cifs_sb,
cifs_sb_master_tcon(cifs_sb));
if (full_path == NULL)
return NULL;
return ERR_PTR(-ENOMEM);

cFYI(1, "Get root dentry for %s", full_path);

Expand Down Expand Up @@ -614,7 +583,7 @@ cifs_get_root(struct smb_vol *vol, struct super_block *sb)
dchild = d_alloc(dparent, &name);
if (dchild == NULL) {
dput(dparent);
dparent = NULL;
dparent = ERR_PTR(-ENOMEM);
goto out;
}
}
Expand All @@ -632,15 +601,15 @@ cifs_get_root(struct smb_vol *vol, struct super_block *sb)
if (rc) {
dput(dchild);
dput(dparent);
dparent = NULL;
dparent = ERR_PTR(rc);
goto out;
}
alias = d_materialise_unique(dchild, inode);
if (alias != NULL) {
dput(dchild);
if (IS_ERR(alias)) {
dput(dparent);
dparent = NULL;
dparent = ERR_PTR(-EINVAL); /* XXX */
goto out;
}
dchild = alias;
Expand All @@ -660,6 +629,13 @@ cifs_get_root(struct smb_vol *vol, struct super_block *sb)
return dparent;
}

static int cifs_set_super(struct super_block *sb, void *data)
{
struct cifs_mnt_data *mnt_data = data;
sb->s_fs_info = mnt_data->cifs_sb;
return set_anon_super(sb, NULL);
}

static struct dentry *
cifs_do_mount(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data)
Expand All @@ -680,75 +656,73 @@ cifs_do_mount(struct file_system_type *fs_type,
cifs_sb = kzalloc(sizeof(struct cifs_sb_info), GFP_KERNEL);
if (cifs_sb == NULL) {
root = ERR_PTR(-ENOMEM);
goto out;
goto out_nls;
}

cifs_sb->mountdata = kstrndup(data, PAGE_SIZE, GFP_KERNEL);
if (cifs_sb->mountdata == NULL) {
root = ERR_PTR(-ENOMEM);
goto out_cifs_sb;
}

cifs_setup_cifs_sb(volume_info, cifs_sb);

rc = cifs_mount(cifs_sb, volume_info);
if (rc) {
if (!(flags & MS_SILENT))
cERROR(1, "cifs_mount failed w/return code = %d", rc);
root = ERR_PTR(rc);
goto out_mountdata;
}

mnt_data.vol = volume_info;
mnt_data.cifs_sb = cifs_sb;
mnt_data.flags = flags;

sb = sget(fs_type, cifs_match_super, set_anon_super, &mnt_data);
sb = sget(fs_type, cifs_match_super, cifs_set_super, &mnt_data);
if (IS_ERR(sb)) {
root = ERR_CAST(sb);
goto out_cifs_sb;
cifs_umount(cifs_sb);
goto out;
}

if (sb->s_fs_info) {
if (sb->s_root) {
cFYI(1, "Use existing superblock");
goto out_shared;
}

/*
* Copy mount params for use in submounts. Better to do
* the copy here and deal with the error before cleanup gets
* complicated post-mount.
*/
cifs_sb->mountdata = kstrndup(data, PAGE_SIZE, GFP_KERNEL);
if (cifs_sb->mountdata == NULL) {
root = ERR_PTR(-ENOMEM);
goto out_super;
}

sb->s_flags = flags;
/* BB should we make this contingent on mount parm? */
sb->s_flags |= MS_NODIRATIME | MS_NOATIME;
sb->s_fs_info = cifs_sb;
cifs_umount(cifs_sb);
} else {
sb->s_flags = flags;
/* BB should we make this contingent on mount parm? */
sb->s_flags |= MS_NODIRATIME | MS_NOATIME;

rc = cifs_read_super(sb);
if (rc) {
root = ERR_PTR(rc);
goto out_super;
}

rc = cifs_read_super(sb, volume_info, dev_name,
flags & MS_SILENT ? 1 : 0);
if (rc) {
root = ERR_PTR(rc);
goto out_super;
sb->s_flags |= MS_ACTIVE;
}

sb->s_flags |= MS_ACTIVE;

root = cifs_get_root(volume_info, sb);
if (root == NULL)
if (IS_ERR(root))
goto out_super;

cFYI(1, "dentry root is: %p", root);
goto out;

out_shared:
root = cifs_get_root(volume_info, sb);
if (root)
cFYI(1, "dentry root is: %p", root);
goto out;

out_super:
kfree(cifs_sb->mountdata);
deactivate_locked_super(sb);

out_cifs_sb:
unload_nls(cifs_sb->local_nls);
kfree(cifs_sb);

out:
cifs_cleanup_volume_info(&volume_info);
return root;

out_mountdata:
kfree(cifs_sb->mountdata);
out_cifs_sb:
kfree(cifs_sb);
out_nls:
unload_nls(volume_info->local_nls);
goto out;
}

static ssize_t cifs_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
Expand Down Expand Up @@ -837,7 +811,7 @@ struct file_system_type cifs_fs_type = {
.owner = THIS_MODULE,
.name = "cifs",
.mount = cifs_do_mount,
.kill_sb = kill_anon_super,
.kill_sb = cifs_kill_sb,
/* .fs_flags */
};
const struct inode_operations cifs_dir_inode_ops = {
Expand Down
8 changes: 4 additions & 4 deletions fs/cifs/cifsproto.h
Expand Up @@ -157,9 +157,8 @@ extern int cifs_match_super(struct super_block *, void *);
extern void cifs_cleanup_volume_info(struct smb_vol **pvolume_info);
extern int cifs_setup_volume_info(struct smb_vol **pvolume_info,
char *mount_data, const char *devname);
extern int cifs_mount(struct super_block *, struct cifs_sb_info *,
struct smb_vol *, const char *);
extern int cifs_umount(struct super_block *, struct cifs_sb_info *);
extern int cifs_mount(struct cifs_sb_info *, struct smb_vol *);
extern void cifs_umount(struct cifs_sb_info *);
extern void cifs_dfs_release_automount_timer(void);
void cifs_proc_init(void);
void cifs_proc_clean(void);
Expand Down Expand Up @@ -218,7 +217,8 @@ extern int get_dfs_path(int xid, struct cifs_ses *pSesInfo,
struct dfs_info3_param **preferrals,
int remap);
extern void reset_cifs_unix_caps(int xid, struct cifs_tcon *tcon,
struct super_block *sb, struct smb_vol *vol);
struct cifs_sb_info *cifs_sb,
struct smb_vol *vol);
extern int CIFSSMBQFSInfo(const int xid, struct cifs_tcon *tcon,
struct kstatfs *FSData);
extern int SMBOldQFSInfo(const int xid, struct cifs_tcon *tcon,
Expand Down

0 comments on commit 804a007

Please sign in to comment.