Commit a0c9a8b8 authored by Al Viro's avatar Al Viro
Browse files

teach vfs_get_tree() to handle subtype, switch do_new_mount() to it



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: default avatarDavid Howells <dhowells@redhat.com>
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 8f291889
Loading
Loading
Loading
Loading
+46 −31
Original line number Diff line number Diff line
@@ -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;
}

+5 −0
Original line number Diff line number Diff line
@@ -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
+1 −1
Original line number Diff line number Diff line
@@ -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 */