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: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
		
							parent
							
								
									fbe0aa1f3d
								
							
						
					
					
						commit
						9d412a43c3
					
				| @ -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 | ||||
|  | ||||
							
								
								
									
										153
									
								
								fs/namespace.c
									
									
									
									
									
								
							
							
						
						
									
										153
									
								
								fs/namespace.c
									
									
									
									
									
								
							| @ -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 @@ out: | ||||
| 	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 @@ fail: | ||||
| 	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); | ||||
|  | ||||
							
								
								
									
										96
									
								
								fs/super.c
									
									
									
									
									
								
							
							
						
						
									
										96
									
								
								fs/super.c
									
									
									
									
									
								
							| @ -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 @@ out: | ||||
| 	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); | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user