From dd8544661947ad6d8d87b3c9d4333bfa1583d1bc Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 17 Jun 2011 08:24:42 -0400 Subject: take bdi setup/destruction into cifs_mount/cifs_umount Acked-by: Pavel Shilovsky Reviewed-by: Jeff Layton Signed-off-by: Al Viro --- fs/cifs/cifsfs.c | 12 +----------- fs/cifs/connect.c | 10 ++++++++++ 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 2f0c58646c1..5d3c4fa4b54 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -116,18 +116,12 @@ cifs_read_super(struct super_block *sb, struct smb_vol *volume_info, spin_lock_init(&cifs_sb->tlink_tree_lock); cifs_sb->tlink_tree = RB_ROOT; - 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; - 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; + return rc; } sb->s_magic = CIFS_MAGIC_NUMBER; @@ -171,9 +165,6 @@ out_no_root: iput(inode); cifs_umount(sb, cifs_sb); - -out_mount_failed: - bdi_destroy(&cifs_sb->bdi); return rc; } @@ -199,7 +190,6 @@ cifs_put_super(struct super_block *sb) } unload_nls(cifs_sb->local_nls); - bdi_destroy(&cifs_sb->bdi); kfree(cifs_sb); } diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 12cf72dd0c4..78fd7557e35 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -2983,6 +2983,13 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, struct tcon_link *tlink; #ifdef CONFIG_CIFS_DFS_UPCALL int referral_walks_count = 0; + + 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; + try_mount_again: /* cleanup activities if we're chasing a referral */ if (referral_walks_count) { @@ -3007,6 +3014,7 @@ try_mount_again: srvTcp = cifs_get_tcp_session(volume_info); if (IS_ERR(srvTcp)) { rc = PTR_ERR(srvTcp); + bdi_destroy(&cifs_sb->bdi); goto out; } @@ -3161,6 +3169,7 @@ mount_fail_check: cifs_put_smb_ses(pSesInfo); else cifs_put_tcp_session(srvTcp); + bdi_destroy(&cifs_sb->bdi); goto out; } @@ -3357,6 +3366,7 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb) } spin_unlock(&cifs_sb->tlink_tree_lock); + bdi_destroy(&cifs_sb->bdi); return 0; } -- cgit v1.2.3 From 6d6861757dfadb7d6aec6bb34acd471210a755f9 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 17 Jun 2011 08:34:57 -0400 Subject: cifs: double free on mount failure if we get to out_super with ->s_root already set (e.g. with cifs_get_root() failure), we'll end up with cifs_put_super() called and ->mountdata freed twice. We'll also get cifs_sb freed twice and cifs_sb->local_nls dropped twice. The problem is, we can get to out_super both with and without ->s_root, which makes ->put_super() a bad place for such work. Switch to ->kill_sb(), have all that work done there after kill_anon_super(). Unlike ->put_super(), ->kill_sb() is called by deactivate_locked_super() whether we have ->s_root or not. Acked-by: Pavel Shilovsky Reviewed-by: Jeff Layton Signed-off-by: Al Viro --- fs/cifs/cifsfs.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 5d3c4fa4b54..dc76c7bccb1 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -184,11 +184,13 @@ cifs_put_super(struct super_block *sb) 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; - } +} +static void cifs_kill_sb(struct super_block *sb) +{ + struct cifs_sb_info *cifs_sb = CIFS_SB(sb); + kill_anon_super(sb); + kfree(cifs_sb->mountdata); unload_nls(cifs_sb->local_nls); kfree(cifs_sb); } @@ -729,8 +731,8 @@ out_shared: goto out; out_super: - kfree(cifs_sb->mountdata); deactivate_locked_super(sb); + goto out; out_cifs_sb: unload_nls(cifs_sb->local_nls); @@ -827,7 +829,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 = { -- cgit v1.2.3 From ca171baaad1420a29cca98be5bdf5596cd70b294 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 17 Jun 2011 08:49:12 -0400 Subject: cifs: don't leak nls on mount failure if cifs_sb allocation fails, we still need to drop nls we'd stashed into volume_info - the one we would've copied to cifs_sb if we could allocate the latter. Acked-by: Pavel Shilovsky Reviewed-by: Jeff Layton Signed-off-by: Al Viro --- fs/cifs/cifsfs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index dc76c7bccb1..bfab2bc8372 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -672,6 +672,7 @@ 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); + unload_nls(volume_info->local_nls); goto out; } -- cgit v1.2.3 From 2c6292ae4be00454882246d07f38cdf15a823c2a Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 17 Jun 2011 09:05:48 -0400 Subject: cifs: don't pass superblock to cifs_mount() To close sget() races we'll need to be able to set cifs_sb up before we get the superblock, so we'll want to be able to do cifs_mount() earlier. Fortunately, it's easy to do - setting ->s_maxbytes can be done in cifs_read_super(), ditto for ->s_time_gran and as for putting MS_POSIXACL into ->s_flags, we can mirror it in ->mnt_cifs_flags until cifs_read_super() is called. Kill unused 'devname' argument, while we are at it... Acked-by: Pavel Shilovsky Reviewed-by: Jeff Layton Signed-off-by: Al Viro --- fs/cifs/cifs_fs_sb.h | 1 + fs/cifs/cifsfs.c | 13 ++++++++++++- fs/cifs/cifsproto.h | 6 +++--- fs/cifs/connect.c | 28 ++++++++++------------------ 4 files changed, 26 insertions(+), 22 deletions(-) diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h index ffb1459dc6e..7260e11e21f 100644 --- a/fs/cifs/cifs_fs_sb.h +++ b/fs/cifs/cifs_fs_sb.h @@ -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; diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index bfab2bc8372..8f7451f3c8e 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -116,7 +116,7 @@ cifs_read_super(struct super_block *sb, struct smb_vol *volume_info, spin_lock_init(&cifs_sb->tlink_tree_lock); cifs_sb->tlink_tree = RB_ROOT; - rc = cifs_mount(sb, cifs_sb, volume_info, devname); + rc = cifs_mount(cifs_sb, volume_info); if (rc) { if (!silent) @@ -124,6 +124,17 @@ cifs_read_super(struct super_block *sb, struct smb_vol *volume_info, return rc; } + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIXACL) + sb->s_flags |= MS_POSIXACL; + + 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; + + /* 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; sb->s_bdi = &cifs_sb->bdi; diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 953f84413c7..5814fe543f9 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -157,8 +157,7 @@ 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_mount(struct cifs_sb_info *, struct smb_vol *); extern int cifs_umount(struct super_block *, struct cifs_sb_info *); extern void cifs_dfs_release_automount_timer(void); void cifs_proc_init(void); @@ -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, diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 78fd7557e35..3011ac8c924 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -2546,7 +2546,7 @@ ip_connect(struct TCP_Server_Info *server) } void reset_cifs_unix_caps(int xid, struct cifs_tcon *tcon, - struct super_block *sb, struct smb_vol *vol_info) + struct cifs_sb_info *cifs_sb, struct smb_vol *vol_info) { /* if we are reconnecting then should we check to see if * any requested capabilities changed locally e.g. via @@ -2600,22 +2600,23 @@ void reset_cifs_unix_caps(int xid, struct cifs_tcon *tcon, cap &= ~CIFS_UNIX_POSIX_ACL_CAP; else if (CIFS_UNIX_POSIX_ACL_CAP & cap) { cFYI(1, "negotiated posix acl support"); - if (sb) - sb->s_flags |= MS_POSIXACL; + if (cifs_sb) + cifs_sb->mnt_cifs_flags |= + CIFS_MOUNT_POSIXACL; } if (vol_info && vol_info->posix_paths == 0) cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP; else if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) { cFYI(1, "negotiate posix pathnames"); - if (sb) - CIFS_SB(sb)->mnt_cifs_flags |= + if (cifs_sb) + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_POSIX_PATHS; } - if (sb && (CIFS_SB(sb)->rsize > 127 * 1024)) { + if (cifs_sb && (cifs_sb->rsize > 127 * 1024)) { if ((cap & CIFS_UNIX_LARGE_READ_CAP) == 0) { - CIFS_SB(sb)->rsize = 127 * 1024; + cifs_sb->rsize = 127 * 1024; cFYI(DBG2, "larger reads not supported by srv"); } } @@ -2971,8 +2972,7 @@ out: } int -cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, - struct smb_vol *volume_info, const char *devname) +cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *volume_info) { int rc = 0; int xid; @@ -3026,14 +3026,6 @@ try_mount_again: goto mount_fail_check; } - if (pSesInfo->capabilities & CAP_LARGE_FILES) - sb->s_maxbytes = MAX_LFS_FILESIZE; - else - sb->s_maxbytes = MAX_NON_LFS; - - /* BB FIXME fix time_gran to be larger for LANMAN sessions */ - sb->s_time_gran = 100; - /* search for existing tcon to this server share */ tcon = cifs_get_tcon(pSesInfo, volume_info); if (IS_ERR(tcon)) { @@ -3046,7 +3038,7 @@ try_mount_again: if (tcon->ses->capabilities & CAP_UNIX) { /* reset of caps checks mount to see if unix extensions disabled for just this mount */ - reset_cifs_unix_caps(xid, tcon, sb, volume_info); + reset_cifs_unix_caps(xid, tcon, cifs_sb, volume_info); if ((tcon->ses->server->tcpStatus == CifsNeedReconnect) && (le64_to_cpu(tcon->fsUnixInfo.Capability) & CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP)) { -- cgit v1.2.3 From d687ca380f1a8f3043f42efd2403cbe58c846e70 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 17 Jun 2011 09:14:27 -0400 Subject: cifs: leak on mount if we share superblock cifs_sb and nls end up leaked... Acked-by: Pavel Shilovsky Reviewed-by: Jeff Layton Signed-off-by: Al Viro --- fs/cifs/cifsfs.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 8f7451f3c8e..4162ee45d04 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -701,6 +701,8 @@ cifs_do_mount(struct file_system_type *fs_type, if (sb->s_fs_info) { cFYI(1, "Use existing superblock"); + unload_nls(cifs_sb->local_nls); + kfree(cifs_sb); goto out_shared; } -- cgit v1.2.3 From 5d3bc605cafe3f367b1c43b673bf643245c81626 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 17 Jun 2011 09:17:28 -0400 Subject: cifs: allocate mountdata earlier pull mountdata allocation up, so that it won't stand in the way when we lift cifs_mount() to location before sget(). Acked-by: Pavel Shilovsky Reviewed-by: Jeff Layton Signed-off-by: Al Viro --- fs/cifs/cifsfs.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 4162ee45d04..ec19161dd27 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -687,6 +687,14 @@ cifs_do_mount(struct file_system_type *fs_type, goto out; } + cifs_sb->mountdata = kstrndup(data, PAGE_SIZE, GFP_KERNEL); + if (cifs_sb->mountdata == NULL) { + root = ERR_PTR(-ENOMEM); + unload_nls(volume_info->local_nls); + kfree(cifs_sb); + goto out; + } + cifs_setup_cifs_sb(volume_info, cifs_sb); mnt_data.vol = volume_info; @@ -701,22 +709,12 @@ cifs_do_mount(struct file_system_type *fs_type, if (sb->s_fs_info) { cFYI(1, "Use existing superblock"); + kfree(cifs_sb->mountdata); unload_nls(cifs_sb->local_nls); kfree(cifs_sb); 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; @@ -749,6 +747,7 @@ out_super: goto out; out_cifs_sb: + kfree(cifs_sb->mountdata); unload_nls(cifs_sb->local_nls); kfree(cifs_sb); -- cgit v1.2.3 From 2ced6f693581357b2a5bf8b031a702c624b12d0d Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 17 Jun 2011 09:20:04 -0400 Subject: cifs: initialize ->tlink_tree in cifs_setup_cifs_sb() no need to wait until cifs_read_super() and we need it done by the time cifs_mount() will be called. Acked-by: Pavel Shilovsky Reviewed-by: Jeff Layton Signed-off-by: Al Viro --- fs/cifs/cifsfs.c | 3 --- fs/cifs/connect.c | 3 +++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index ec19161dd27..61c7aa870f1 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -113,9 +113,6 @@ cifs_read_super(struct super_block *sb, struct smb_vol *volume_info, cifs_sb = CIFS_SB(sb); - spin_lock_init(&cifs_sb->tlink_tree_lock); - cifs_sb->tlink_tree = RB_ROOT; - rc = cifs_mount(cifs_sb, volume_info); if (rc) { diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 3011ac8c924..9f09adf51ed 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -2663,6 +2663,9 @@ void cifs_setup_cifs_sb(struct smb_vol *pvolume_info, { INIT_DELAYED_WORK(&cifs_sb->prune_tlinks, cifs_prune_tlinks); + spin_lock_init(&cifs_sb->tlink_tree_lock); + cifs_sb->tlink_tree = RB_ROOT; + if (pvolume_info->rsize > CIFSMaxBufSize) { cERROR(1, "rsize %d too large, using MaxBufSize", pvolume_info->rsize); -- cgit v1.2.3 From 2a9b99516c662d1713d58648e4a4c9aef72051bc Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 17 Jun 2011 09:27:16 -0400 Subject: sanitize cifs_umount() prototype a) superblock argument is unused b) it always returns 0 Acked-by: Pavel Shilovsky Reviewed-by: Jeff Layton Signed-off-by: Al Viro --- fs/cifs/cifsfs.c | 6 ++---- fs/cifs/cifsproto.h | 2 +- fs/cifs/connect.c | 5 ++--- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 61c7aa870f1..2af14d4577a 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -172,7 +172,7 @@ out_no_root: if (inode) iput(inode); - cifs_umount(sb, cifs_sb); + cifs_umount(cifs_sb); return rc; } @@ -189,9 +189,7 @@ cifs_put_super(struct super_block *sb) return; } - rc = cifs_umount(sb, cifs_sb); - if (rc) - cERROR(1, "cifs_umount failed with return code %d", rc); + cifs_umount(cifs_sb); } static void cifs_kill_sb(struct super_block *sb) diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 5814fe543f9..257f312ede4 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -158,7 +158,7 @@ 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 cifs_sb_info *, struct smb_vol *); -extern int cifs_umount(struct super_block *, struct cifs_sb_info *); +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); diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 9f09adf51ed..b2702226634 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -3339,8 +3339,8 @@ CIFSTCon(unsigned int xid, struct cifs_ses *ses, return rc; } -int -cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb) +void +cifs_umount(struct cifs_sb_info *cifs_sb) { struct rb_root *root = &cifs_sb->tlink_tree; struct rb_node *node; @@ -3362,7 +3362,6 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb) spin_unlock(&cifs_sb->tlink_tree_lock); bdi_destroy(&cifs_sb->bdi); - return 0; } int cifs_negotiate_protocol(unsigned int xid, struct cifs_ses *ses) -- cgit v1.2.3 From 97d1152acec0647b72f8c6ecc57da0d6fed574de Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 17 Jun 2011 09:29:57 -0400 Subject: cifs: pull cifs_mount() call up ... to the point prior to sget(). Now we have cifs_sb set up early enough. Acked-by: Pavel Shilovsky Reviewed-by: Jeff Layton Signed-off-by: Al Viro --- fs/cifs/cifsfs.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 2af14d4577a..4004bc647a7 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -104,8 +104,7 @@ 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; @@ -113,14 +112,6 @@ cifs_read_super(struct super_block *sb, struct smb_vol *volume_info, cifs_sb = CIFS_SB(sb); - rc = cifs_mount(cifs_sb, volume_info); - - if (rc) { - if (!silent) - cERROR(1, "cifs_mount failed w/return code = %d", rc); - return rc; - } - if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIXACL) sb->s_flags |= MS_POSIXACL; @@ -692,6 +683,17 @@ cifs_do_mount(struct file_system_type *fs_type, 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); + unload_nls(volume_info->local_nls); + kfree(cifs_sb->mountdata); + kfree(cifs_sb); + goto out; + } + mnt_data.vol = volume_info; mnt_data.cifs_sb = cifs_sb; mnt_data.flags = flags; @@ -699,11 +701,13 @@ cifs_do_mount(struct file_system_type *fs_type, sb = sget(fs_type, cifs_match_super, set_anon_super, &mnt_data); if (IS_ERR(sb)) { root = ERR_CAST(sb); + cifs_umount(cifs_sb); goto out_cifs_sb; } if (sb->s_fs_info) { cFYI(1, "Use existing superblock"); + cifs_umount(cifs_sb); kfree(cifs_sb->mountdata); unload_nls(cifs_sb->local_nls); kfree(cifs_sb); @@ -715,8 +719,7 @@ cifs_do_mount(struct file_system_type *fs_type, sb->s_flags |= MS_NODIRATIME | MS_NOATIME; sb->s_fs_info = cifs_sb; - rc = cifs_read_super(sb, volume_info, dev_name, - flags & MS_SILENT ? 1 : 0); + rc = cifs_read_super(sb); if (rc) { root = ERR_PTR(rc); goto out_super; -- cgit v1.2.3 From 98ab494dd1d25388981114057cf9446250cc7dc7 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 17 Jun 2011 09:32:10 -0400 Subject: cifs: move cifs_umount() call into ->kill_sb() instead of calling it manually in case if cifs_read_super() fails to set ->s_root, just call it from ->kill_sb(). cifs_put_super() is gone now *and* we have cifs_sb shutdown and destruction done after the superblock is gone from ->s_instances. Acked-by: Pavel Shilovsky Reviewed-by: Jeff Layton Signed-off-by: Al Viro --- fs/cifs/cifsfs.c | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 4004bc647a7..15de4561dbc 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -163,30 +163,14 @@ out_no_root: if (inode) iput(inode); - cifs_umount(cifs_sb); return rc; } -static void -cifs_put_super(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; - } - - cifs_umount(cifs_sb); -} - static void cifs_kill_sb(struct super_block *sb) { struct cifs_sb_info *cifs_sb = CIFS_SB(sb); kill_anon_super(sb); + cifs_umount(cifs_sb); kfree(cifs_sb->mountdata); unload_nls(cifs_sb->local_nls); kfree(cifs_sb); @@ -537,7 +521,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, -- cgit v1.2.3 From d757d71bfc30669a500b72792067e8d1c5d401a5 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 17 Jun 2011 09:42:43 -0400 Subject: cifs: pull freeing mountdata/dropping nls/freeing cifs_sb into cifs_umount() all callers of cifs_umount() proceed to do the same thing; pull it into cifs_umount() itself. Acked-by: Pavel Shilovsky Reviewed-by: Jeff Layton Signed-off-by: Al Viro --- fs/cifs/cifsfs.c | 15 +-------------- fs/cifs/connect.c | 3 +++ 2 files changed, 4 insertions(+), 14 deletions(-) diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 15de4561dbc..46960b7ee43 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -171,9 +171,6 @@ static void cifs_kill_sb(struct super_block *sb) struct cifs_sb_info *cifs_sb = CIFS_SB(sb); kill_anon_super(sb); cifs_umount(cifs_sb); - kfree(cifs_sb->mountdata); - unload_nls(cifs_sb->local_nls); - kfree(cifs_sb); } static int @@ -685,15 +682,12 @@ cifs_do_mount(struct file_system_type *fs_type, if (IS_ERR(sb)) { root = ERR_CAST(sb); cifs_umount(cifs_sb); - goto out_cifs_sb; + goto out; } if (sb->s_fs_info) { cFYI(1, "Use existing superblock"); cifs_umount(cifs_sb); - kfree(cifs_sb->mountdata); - unload_nls(cifs_sb->local_nls); - kfree(cifs_sb); goto out_shared; } @@ -725,13 +719,6 @@ out_shared: out_super: deactivate_locked_super(sb); - goto out; - -out_cifs_sb: - kfree(cifs_sb->mountdata); - unload_nls(cifs_sb->local_nls); - kfree(cifs_sb); - out: cifs_cleanup_volume_info(&volume_info); return root; diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index b2702226634..ca7fbe3d51a 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -3362,6 +3362,9 @@ cifs_umount(struct cifs_sb_info *cifs_sb) spin_unlock(&cifs_sb->tlink_tree_lock); bdi_destroy(&cifs_sb->bdi); + kfree(cifs_sb->mountdata); + unload_nls(cifs_sb->local_nls); + kfree(cifs_sb); } int cifs_negotiate_protocol(unsigned int xid, struct cifs_ses *ses) -- cgit v1.2.3 From ee01a14d9ddcf3f832f9ceb837888501cb496e27 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 17 Jun 2011 09:47:23 -0400 Subject: cifs: close sget() races have ->s_fs_info set by the set() callback passed to sget() Acked-by: Pavel Shilovsky Reviewed-by: Jeff Layton Signed-off-by: Al Viro --- fs/cifs/cifsfs.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 46960b7ee43..ba2b2da360d 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -629,6 +629,13 @@ out: 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) @@ -678,14 +685,14 @@ cifs_do_mount(struct file_system_type *fs_type, 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); cifs_umount(cifs_sb); goto out; } - if (sb->s_fs_info) { + if (sb->s_root) { cFYI(1, "Use existing superblock"); cifs_umount(cifs_sb); goto out_shared; @@ -694,7 +701,6 @@ cifs_do_mount(struct file_system_type *fs_type, 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; rc = cifs_read_super(sb); if (rc) { -- cgit v1.2.3 From fa18f1bdce898f0efd0c8639c901d826d01be04f Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 17 Jun 2011 09:50:44 -0400 Subject: cifs: more breakage on mount failures if cifs_get_root() fails, we end up with ->mount() returning NULL, which is not what callers expect. Moreover, in case of superblock reuse we end up leaking a superblock reference... Acked-by: Pavel Shilovsky Reviewed-by: Jeff Layton Signed-off-by: Al Viro --- fs/cifs/cifsfs.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index ba2b2da360d..234e9d08db7 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -710,19 +710,16 @@ cifs_do_mount(struct file_system_type *fs_type, sb->s_flags |= MS_ACTIVE; +out_shared: root = cifs_get_root(volume_info, sb); - if (root == NULL) + if (root == NULL) { + root = ERR_PTR(-EINVAL); /* XXX */ 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: deactivate_locked_super(sb); out: -- cgit v1.2.3 From 5c4f1ad7c6aa3b729bd3a93b80f9417d7e978c32 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 17 Jun 2011 09:56:55 -0400 Subject: cifs: tidy cifs_do_mount() up a bit Acked-by: Pavel Shilovsky Reviewed-by: Jeff Layton Signed-off-by: Al Viro --- fs/cifs/cifsfs.c | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 234e9d08db7..9a6696a5eb7 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -656,16 +656,13 @@ 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); - unload_nls(volume_info->local_nls); - goto out; + goto out_nls; } cifs_sb->mountdata = kstrndup(data, PAGE_SIZE, GFP_KERNEL); if (cifs_sb->mountdata == NULL) { root = ERR_PTR(-ENOMEM); - unload_nls(volume_info->local_nls); - kfree(cifs_sb); - goto out; + goto out_cifs_sb; } cifs_setup_cifs_sb(volume_info, cifs_sb); @@ -675,10 +672,7 @@ cifs_do_mount(struct file_system_type *fs_type, if (!(flags & MS_SILENT)) cERROR(1, "cifs_mount failed w/return code = %d", rc); root = ERR_PTR(rc); - unload_nls(volume_info->local_nls); - kfree(cifs_sb->mountdata); - kfree(cifs_sb); - goto out; + goto out_mountdata; } mnt_data.vol = volume_info; @@ -695,22 +689,20 @@ cifs_do_mount(struct file_system_type *fs_type, if (sb->s_root) { cFYI(1, "Use existing superblock"); cifs_umount(cifs_sb); - goto out_shared; - } - - sb->s_flags = flags; - /* BB should we make this contingent on mount parm? */ - sb->s_flags |= MS_NODIRATIME | MS_NOATIME; + } 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); - if (rc) { - root = ERR_PTR(rc); - goto out_super; + sb->s_flags |= MS_ACTIVE; } - sb->s_flags |= MS_ACTIVE; - -out_shared: root = cifs_get_root(volume_info, sb); if (root == NULL) { root = ERR_PTR(-EINVAL); /* XXX */ @@ -725,6 +717,14 @@ out_super: 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, -- cgit v1.2.3 From 9403c9c598e91d473c0582066e47ed2289292e45 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 17 Jun 2011 10:02:59 -0400 Subject: cifs: propagate errors from cifs_get_root() to mount(2) ... instead of just failing with -EINVAL Acked-by: Pavel Shilovsky Reviewed-by: Jeff Layton Signed-off-by: Al Viro --- fs/cifs/cifsfs.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 9a6696a5eb7..35f9154615f 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -554,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); @@ -583,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; } } @@ -601,7 +601,7 @@ 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); @@ -609,7 +609,7 @@ cifs_get_root(struct smb_vol *vol, struct super_block *sb) dput(dchild); if (IS_ERR(alias)) { dput(dparent); - dparent = NULL; + dparent = ERR_PTR(-EINVAL); /* XXX */ goto out; } dchild = alias; @@ -704,10 +704,8 @@ cifs_do_mount(struct file_system_type *fs_type, } root = cifs_get_root(volume_info, sb); - if (root == NULL) { - root = ERR_PTR(-EINVAL); /* XXX */ + if (IS_ERR(root)) goto out_super; - } cFYI(1, "dentry root is: %p", root); goto out; -- cgit v1.2.3