Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9d412a43 authored by Al Viro's avatar Al Viro
Browse files

vfs: split off vfsmount-related parts of vfs_kern_mount()



new function: mount_fs().  Does all work done by vfs_kern_mount()
except the allocation and filling of vfsmount; returns root dentry
or ERR_PTR().

vfs_kern_mount() switched to using it and taken to fs/namespace.c,
along with its wrappers.

alloc_vfsmnt()/free_vfsmnt() made static.

functions in namespace.c slightly reordered.

Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent fbe0aa1f
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@
#include <linux/lglock.h>

struct super_block;
struct file_system_type;
struct linux_binprm;
struct path;

@@ -61,8 +62,6 @@ extern int check_unsafe_exec(struct linux_binprm *);
extern int copy_mount_options(const void __user *, unsigned long *);
extern int copy_mount_string(const void __user *, char **);

extern void free_vfsmnt(struct vfsmount *);
extern struct vfsmount *alloc_vfsmnt(const char *);
extern unsigned int mnt_get_count(struct vfsmount *mnt);
extern struct vfsmount *__lookup_mnt(struct vfsmount *, struct dentry *, int);
extern void mnt_set_mountpoint(struct vfsmount *, struct dentry *,
@@ -99,6 +98,8 @@ extern struct file *get_empty_filp(void);
extern int do_remount_sb(struct super_block *, int, void *, int);
extern void __put_super(struct super_block *sb);
extern void put_super(struct super_block *sb);
extern struct dentry *mount_fs(struct file_system_type *,
			       int, const char *, void *);

/*
 * open.c
+113 −40
Original line number Diff line number Diff line
@@ -196,7 +196,7 @@ unsigned int mnt_get_count(struct vfsmount *mnt)
#endif
}

struct vfsmount *alloc_vfsmnt(const char *name)
static struct vfsmount *alloc_vfsmnt(const char *name)
{
	struct vfsmount *mnt = kmem_cache_zalloc(mnt_cache, GFP_KERNEL);
	if (mnt) {
@@ -466,7 +466,7 @@ static void __mnt_unmake_readonly(struct vfsmount *mnt)
	br_write_unlock(vfsmount_lock);
}

void free_vfsmnt(struct vfsmount *mnt)
static void free_vfsmnt(struct vfsmount *mnt)
{
	kfree(mnt->mnt_devname);
	mnt_free_id(mnt);
@@ -670,6 +670,36 @@ static struct vfsmount *skip_mnt_tree(struct vfsmount *p)
	return p;
}

struct vfsmount *
vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void *data)
{
	struct vfsmount *mnt;
	struct dentry *root;

	if (!type)
		return ERR_PTR(-ENODEV);

	mnt = alloc_vfsmnt(name);
	if (!mnt)
		return ERR_PTR(-ENOMEM);

	if (flags & MS_KERNMOUNT)
		mnt->mnt_flags = MNT_INTERNAL;

	root = mount_fs(type, flags, name, data);
	if (IS_ERR(root)) {
		free_vfsmnt(mnt);
		return ERR_CAST(root);
	}

	mnt->mnt_root = root;
	mnt->mnt_sb = root->d_sb;
	mnt->mnt_mountpoint = mnt->mnt_root;
	mnt->mnt_parent = mnt;
	return mnt;
}
EXPORT_SYMBOL_GPL(vfs_kern_mount);

static struct vfsmount *clone_mnt(struct vfsmount *old, struct dentry *root,
					int flag)
{
@@ -1905,7 +1935,81 @@ static int do_move_mount(struct path *path, char *old_name)
	return err;
}

static int do_add_mount(struct vfsmount *, struct path *, int);
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);
}

struct vfsmount *
do_kern_mount(const char *fstype, int flags, const char *name, void *data)
{
	struct file_system_type *type = get_fs_type(fstype);
	struct vfsmount *mnt;
	if (!type)
		return ERR_PTR(-ENODEV);
	mnt = vfs_kern_mount(type, flags, name, data);
	if (!IS_ERR(mnt) && (type->fs_flags & FS_HAS_SUBTYPE) &&
	    !mnt->mnt_sb->s_subtype)
		mnt = fs_set_subtype(mnt, fstype);
	put_filesystem(type);
	return mnt;
}
EXPORT_SYMBOL_GPL(do_kern_mount);

/*
 * add a mount into a namespace's mount tree
 */
static int do_add_mount(struct vfsmount *newmnt, struct path *path, int mnt_flags)
{
	int err;

	mnt_flags &= ~(MNT_SHARED | MNT_WRITE_HOLD | MNT_INTERNAL);

	down_write(&namespace_sem);
	/* Something was mounted here while we slept */
	err = follow_down(path, true);
	if (err < 0)
		goto unlock;

	err = -EINVAL;
	if (!(mnt_flags & MNT_SHRINKABLE) && !check_mnt(path->mnt))
		goto unlock;

	/* Refuse the same filesystem on the same mount point */
	err = -EBUSY;
	if (path->mnt->mnt_sb == newmnt->mnt_sb &&
	    path->mnt->mnt_root == path->dentry)
		goto unlock;

	err = -EINVAL;
	if (S_ISLNK(newmnt->mnt_root->d_inode->i_mode))
		goto unlock;

	newmnt->mnt_flags = mnt_flags;
	err = graft_tree(newmnt, path);

unlock:
	up_write(&namespace_sem);
	return err;
}

/*
 * create a new mount for userspace and request it to be added into the
@@ -1965,43 +2069,6 @@ int finish_automount(struct vfsmount *m, struct path *path)
	return err;
}

/*
 * add a mount into a namespace's mount tree
 */
static int do_add_mount(struct vfsmount *newmnt, struct path *path, int mnt_flags)
{
	int err;

	mnt_flags &= ~(MNT_SHARED | MNT_WRITE_HOLD | MNT_INTERNAL);

	down_write(&namespace_sem);
	/* Something was mounted here while we slept */
	err = follow_down(path, true);
	if (err < 0)
		goto unlock;

	err = -EINVAL;
	if (!(mnt_flags & MNT_SHRINKABLE) && !check_mnt(path->mnt))
		goto unlock;

	/* Refuse the same filesystem on the same mount point */
	err = -EBUSY;
	if (path->mnt->mnt_sb == newmnt->mnt_sb &&
	    path->mnt->mnt_root == path->dentry)
		goto unlock;

	err = -EINVAL;
	if (S_ISLNK(newmnt->mnt_root->d_inode->i_mode))
		goto unlock;

	newmnt->mnt_flags = mnt_flags;
	err = graft_tree(newmnt, path);

unlock:
	up_write(&namespace_sem);
	return err;
}

/**
 * mnt_set_expiry - Put a mount on an expiration list
 * @mnt: The mount to list.
@@ -2660,3 +2727,9 @@ void put_mnt_ns(struct mnt_namespace *ns)
	kfree(ns);
}
EXPORT_SYMBOL(put_mnt_ns);

struct vfsmount *kern_mount_data(struct file_system_type *type, void *data)
{
	return vfs_kern_mount(type, MS_KERNMOUNT, type->name, data);
}
EXPORT_SYMBOL_GPL(kern_mount_data);
+16 −80
Original line number Diff line number Diff line
@@ -910,29 +910,18 @@ struct dentry *mount_single(struct file_system_type *fs_type,
}
EXPORT_SYMBOL(mount_single);

struct vfsmount *
vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void *data)
struct dentry *
mount_fs(struct file_system_type *type, int flags, const char *name, void *data)
{
	struct vfsmount *mnt;
	struct dentry *root;
	struct super_block *sb;
	char *secdata = NULL;
	int error;

	if (!type)
		return ERR_PTR(-ENODEV);

	error = -ENOMEM;
	mnt = alloc_vfsmnt(name);
	if (!mnt)
		goto out;

	if (flags & MS_KERNMOUNT)
		mnt->mnt_flags = MNT_INTERNAL;
	int error = -ENOMEM;

	if (data && !(type->fs_flags & FS_BINARY_MOUNTDATA)) {
		secdata = alloc_secdata();
		if (!secdata)
			goto out_mnt;
			goto out;

		error = security_sb_copy_data(data, secdata);
		if (error)
@@ -944,13 +933,12 @@ vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void
		error = PTR_ERR(root);
		goto out_free_secdata;
	}
	mnt->mnt_root = root;
	mnt->mnt_sb = root->d_sb;
	BUG_ON(!mnt->mnt_sb);
	WARN_ON(!mnt->mnt_sb->s_bdi);
	mnt->mnt_sb->s_flags |= MS_BORN;
	sb = root->d_sb;
	BUG_ON(!sb);
	WARN_ON(!sb->s_bdi);
	sb->s_flags |= MS_BORN;

	error = security_sb_kern_mount(mnt->mnt_sb, flags, secdata);
	error = security_sb_kern_mount(sb, flags, secdata);
	if (error)
		goto out_sb;

@@ -961,27 +949,21 @@ vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void
	 * violate this rule. This warning should be either removed or
	 * converted to a BUG() in 2.6.34.
	 */
	WARN((mnt->mnt_sb->s_maxbytes < 0), "%s set sb->s_maxbytes to "
		"negative value (%lld)\n", type->name, mnt->mnt_sb->s_maxbytes);
	WARN((sb->s_maxbytes < 0), "%s set sb->s_maxbytes to "
		"negative value (%lld)\n", type->name, sb->s_maxbytes);

	mnt->mnt_mountpoint = mnt->mnt_root;
	mnt->mnt_parent = mnt;
	up_write(&mnt->mnt_sb->s_umount);
	up_write(&sb->s_umount);
	free_secdata(secdata);
	return mnt;
	return root;
out_sb:
	dput(mnt->mnt_root);
	deactivate_locked_super(mnt->mnt_sb);
	dput(root);
	deactivate_locked_super(sb);
out_free_secdata:
	free_secdata(secdata);
out_mnt:
	free_vfsmnt(mnt);
out:
	return ERR_PTR(error);
}

EXPORT_SYMBOL_GPL(vfs_kern_mount);

/**
 * freeze_super - lock the filesystem and force it into a consistent state
 * @sb: the super to lock
@@ -1071,49 +1053,3 @@ int thaw_super(struct super_block *sb)
	return 0;
}
EXPORT_SYMBOL(thaw_super);

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);
}

struct vfsmount *
do_kern_mount(const char *fstype, int flags, const char *name, void *data)
{
	struct file_system_type *type = get_fs_type(fstype);
	struct vfsmount *mnt;
	if (!type)
		return ERR_PTR(-ENODEV);
	mnt = vfs_kern_mount(type, flags, name, data);
	if (!IS_ERR(mnt) && (type->fs_flags & FS_HAS_SUBTYPE) &&
	    !mnt->mnt_sb->s_subtype)
		mnt = fs_set_subtype(mnt, fstype);
	put_filesystem(type);
	return mnt;
}
EXPORT_SYMBOL_GPL(do_kern_mount);

struct vfsmount *kern_mount_data(struct file_system_type *type, void *data)
{
	return vfs_kern_mount(type, MS_KERNMOUNT, type->name, data);
}

EXPORT_SYMBOL_GPL(kern_mount_data);