]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 27 Jun 2011 02:39:22 +0000 (19:39 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 27 Jun 2011 02:39:22 +0000 (19:39 -0700)
* '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>
fs/cifs/cifs_fs_sb.h
fs/cifs/cifsfs.c
fs/cifs/cifsproto.h
fs/cifs/connect.c

index ffb1459dc6ecf04f2da417a85c734374177f45ce..7260e11e21f8429304b519b2ec0f5aeb477ce0b9 100644 (file)
@@ -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;
index 2f0c58646c10506ed180484cb80b6869babcfd0b..35f9154615fa5ca7cc01fe857324b640b9533245 100644 (file)
@@ -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,22 +112,16 @@ 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;
+       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;
@@ -170,37 +163,14 @@ out_no_root:
        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
@@ -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,
@@ -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);
 
@@ -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;
                        }
                }
@@ -632,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);
@@ -640,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;
@@ -660,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)
@@ -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,
@@ -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 = {
index 953f84413c771b1cb0e3bb404a4349f7d90b08fa..257f312ede422d6e5c1592954bb9467f602c6e6a 100644 (file)
@@ -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);
@@ -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,
index c761935eab8cdc4f86ca6f5d58badd88709229a3..7f540df5252786b41d0af7c6bf3846a825069cb4 100644 (file)
@@ -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");
                        }
                }
@@ -2662,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);
@@ -2982,8 +2986,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;
@@ -2994,6 +2997,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) {
@@ -3018,6 +3028,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;
        }
 
@@ -3029,14 +3040,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)) {
@@ -3049,7 +3052,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)) {
@@ -3172,6 +3175,7 @@ mount_fail_check:
                        cifs_put_smb_ses(pSesInfo);
                else
                        cifs_put_tcp_session(srvTcp);
+               bdi_destroy(&cifs_sb->bdi);
                goto out;
        }
 
@@ -3346,8 +3350,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;
@@ -3368,7 +3372,10 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
        }
        spin_unlock(&cifs_sb->tlink_tree_lock);
 
-       return 0;
+       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)