teach vfs_get_tree() to handle subtype, switch do_new_mount() to it
authorAl Viro <viro@zeniv.linux.org.uk>
Sun, 4 Nov 2018 12:18:51 +0000 (07:18 -0500)
committerAl Viro <viro@zeniv.linux.org.uk>
Wed, 30 Jan 2019 22:44:25 +0000 (17:44 -0500)
Roll the handling of subtypes into do_new_mount() and vfs_get_tree().  The
former determines any subtype string and hangs it off the fs_context; the
latter applies it.

Make do_new_mount() create, parameterise and commit an fs_context and
create a mount for itself rather than calling vfs_kern_mount().

[AV -- missing kstrdup()]
[AV -- ... and no kstrdup() if we get to setting ->s_submount - we
simply transfer it from fc, leaving NULL behind]
[AV -- constify ->s_submount, while we are at it]

Reviewed-by: David Howells <dhowells@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
fs/namespace.c
fs/super.c
include/linux/fs.h

index 156771f5745a227127e0788b6c6a4bfad7cfea32..0354cb6ac2d37b357bd217f1a42c8b78207510aa 100644 (file)
@@ -2479,29 +2479,6 @@ out:
        return err;
 }
 
-static struct vfsmount *fs_set_subtype(struct vfsmount *mnt, const char *fstype)
-{
-       int err;
-       const char *subtype = strchr(fstype, '.');
-       if (subtype) {
-               subtype++;
-               err = -EINVAL;
-               if (!subtype[0])
-                       goto err;
-       } else
-               subtype = "";
-
-       mnt->mnt_sb->s_subtype = kstrdup(subtype, GFP_KERNEL);
-       err = -ENOMEM;
-       if (!mnt->mnt_sb->s_subtype)
-               goto err;
-       return mnt;
-
- err:
-       mntput(mnt);
-       return ERR_PTR(err);
-}
-
 /*
  * add a mount into a namespace's mount tree
  */
@@ -2557,7 +2534,9 @@ static int do_new_mount(struct path *path, const char *fstype, int sb_flags,
 {
        struct file_system_type *type;
        struct vfsmount *mnt;
-       int err;
+       struct fs_context *fc;
+       const char *subtype = NULL;
+       int err = 0;
 
        if (!fstype)
                return -EINVAL;
@@ -2566,23 +2545,59 @@ static int do_new_mount(struct path *path, const char *fstype, int sb_flags,
        if (!type)
                return -ENODEV;
 
-       mnt = vfs_kern_mount(type, sb_flags, name, data);
-       if (!IS_ERR(mnt) && (type->fs_flags & FS_HAS_SUBTYPE) &&
-           !mnt->mnt_sb->s_subtype)
-               mnt = fs_set_subtype(mnt, fstype);
+       if (type->fs_flags & FS_HAS_SUBTYPE) {
+               subtype = strchr(fstype, '.');
+               if (subtype) {
+                       subtype++;
+                       if (!*subtype) {
+                               put_filesystem(type);
+                               return -EINVAL;
+                       }
+               } else {
+                       subtype = "";
+               }
+       }
 
+       fc = fs_context_for_mount(type, sb_flags);
        put_filesystem(type);
-       if (IS_ERR(mnt))
-               return PTR_ERR(mnt);
+       if (IS_ERR(fc))
+               return PTR_ERR(fc);
+
+       if (subtype) {
+               fc->subtype = kstrdup(subtype, GFP_KERNEL);
+               if (!fc->subtype)
+                       err = -ENOMEM;
+       }
+       if (!err && name) {
+               fc->source = kstrdup(name, GFP_KERNEL);
+               if (!fc->source)
+                       err = -ENOMEM;
+       }
+       if (!err)
+               err = parse_monolithic_mount_data(fc, data);
+       if (!err)
+               err = vfs_get_tree(fc);
+       if (err)
+               goto out;
+
+       up_write(&fc->root->d_sb->s_umount);
+       mnt = vfs_create_mount(fc);
+       if (IS_ERR(mnt)) {
+               err = PTR_ERR(mnt);
+               goto out;
+       }
 
        if (mount_too_revealing(mnt, &mnt_flags)) {
                mntput(mnt);
-               return -EPERM;
+               err = -EPERM;
+               goto out;
        }
 
        err = do_add_mount(real_mount(mnt), path, mnt_flags);
        if (err)
                mntput(mnt);
+out:
+       put_fs_context(fc);
        return err;
 }
 
index fc3887277ad19983d0a3f7380d7c2827fddfbca2..b91b6df05b67c347c2e7d5dbd890bb3b0e922b7c 100644 (file)
@@ -1262,6 +1262,11 @@ int vfs_get_tree(struct fs_context *fc)
        sb = fc->root->d_sb;
        WARN_ON(!sb->s_bdi);
 
+       if (fc->subtype && !sb->s_subtype) {
+               sb->s_subtype = fc->subtype;
+               fc->subtype = NULL;
+       }
+
        /*
         * Write barrier is for super_cache_count(). We place it before setting
         * SB_BORN as the data dependency between the two functions is the
index 811c77743dad2870282e6c3c85e8f238f8643767..36fff12ab8904f9eaec8b1f8164eb0eaddf3c37f 100644 (file)
@@ -1447,7 +1447,7 @@ struct super_block {
         * Filesystem subtype.  If non-empty the filesystem type field
         * in /proc/mounts will be "type.subtype"
         */
-       char *s_subtype;
+       const char *s_subtype;
 
        const struct dentry_operations *s_d_op; /* default d_op for dentries */