diff options
Diffstat (limited to 'fs/sysfs/mount.c')
| -rw-r--r-- | fs/sysfs/mount.c | 188 | 
1 files changed, 29 insertions, 159 deletions
diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c index 834ec2cdb7a..8a49486bf30 100644 --- a/fs/sysfs/mount.c +++ b/fs/sysfs/mount.c @@ -13,147 +13,45 @@  #define DEBUG  #include <linux/fs.h> +#include <linux/magic.h>  #include <linux/mount.h> -#include <linux/pagemap.h>  #include <linux/init.h> -#include <linux/module.h> -#include <linux/magic.h> -#include <linux/slab.h>  #include <linux/user_namespace.h>  #include "sysfs.h" - -static struct vfsmount *sysfs_mnt; -struct kmem_cache *sysfs_dir_cachep; - -static const struct super_operations sysfs_ops = { -	.statfs		= simple_statfs, -	.drop_inode	= generic_delete_inode, -	.evict_inode	= sysfs_evict_inode, -}; - -struct sysfs_dirent sysfs_root = { -	.s_name		= "", -	.s_count	= ATOMIC_INIT(1), -	.s_flags	= SYSFS_DIR | (KOBJ_NS_TYPE_NONE << SYSFS_NS_TYPE_SHIFT), -	.s_mode		= S_IFDIR | S_IRUGO | S_IXUGO, -	.s_ino		= 1, -}; - -static int sysfs_fill_super(struct super_block *sb, void *data, int silent) -{ -	struct inode *inode; -	struct dentry *root; - -	sb->s_blocksize = PAGE_CACHE_SIZE; -	sb->s_blocksize_bits = PAGE_CACHE_SHIFT; -	sb->s_magic = SYSFS_MAGIC; -	sb->s_op = &sysfs_ops; -	sb->s_time_gran = 1; - -	/* get root inode, initialize and unlock it */ -	mutex_lock(&sysfs_mutex); -	inode = sysfs_get_inode(sb, &sysfs_root); -	mutex_unlock(&sysfs_mutex); -	if (!inode) { -		pr_debug("sysfs: could not get root inode\n"); -		return -ENOMEM; -	} - -	/* instantiate and link root dentry */ -	root = d_make_root(inode); -	if (!root) { -		pr_debug("%s: could not get root dentry!\n", __func__); -		return -ENOMEM; -	} -	root->d_fsdata = &sysfs_root; -	sb->s_root = root; -	sb->s_d_op = &sysfs_dentry_ops; -	return 0; -} - -static int sysfs_test_super(struct super_block *sb, void *data) -{ -	struct sysfs_super_info *sb_info = sysfs_info(sb); -	struct sysfs_super_info *info = data; -	enum kobj_ns_type type; -	int found = 1; - -	for (type = KOBJ_NS_TYPE_NONE; type < KOBJ_NS_TYPES; type++) { -		if (sb_info->ns[type] != info->ns[type]) -			found = 0; -	} -	return found; -} - -static int sysfs_set_super(struct super_block *sb, void *data) -{ -	int error; -	error = set_anon_super(sb, data); -	if (!error) -		sb->s_fs_info = data; -	return error; -} - -static void free_sysfs_super_info(struct sysfs_super_info *info) -{ -	int type; -	for (type = KOBJ_NS_TYPE_NONE; type < KOBJ_NS_TYPES; type++) -		kobj_ns_drop(type, info->ns[type]); -	kfree(info); -} +static struct kernfs_root *sysfs_root; +struct kernfs_node *sysfs_root_kn;  static struct dentry *sysfs_mount(struct file_system_type *fs_type,  	int flags, const char *dev_name, void *data)  { -	struct sysfs_super_info *info; -	enum kobj_ns_type type; -	struct super_block *sb; -	int error; +	struct dentry *root; +	void *ns; +	bool new_sb;  	if (!(flags & MS_KERNMOUNT)) {  		if (!capable(CAP_SYS_ADMIN) && !fs_fully_visible(fs_type))  			return ERR_PTR(-EPERM); -		for (type = KOBJ_NS_TYPE_NONE; type < KOBJ_NS_TYPES; type++) { -			if (!kobj_ns_current_may_mount(type)) -				return ERR_PTR(-EPERM); -		} -	} - -	info = kzalloc(sizeof(*info), GFP_KERNEL); -	if (!info) -		return ERR_PTR(-ENOMEM); - -	for (type = KOBJ_NS_TYPE_NONE; type < KOBJ_NS_TYPES; type++) -		info->ns[type] = kobj_ns_grab_current(type); - -	sb = sget(fs_type, sysfs_test_super, sysfs_set_super, flags, info); -	if (IS_ERR(sb) || sb->s_fs_info != info) -		free_sysfs_super_info(info); -	if (IS_ERR(sb)) -		return ERR_CAST(sb); -	if (!sb->s_root) { -		error = sysfs_fill_super(sb, data, flags & MS_SILENT ? 1 : 0); -		if (error) { -			deactivate_locked_super(sb); -			return ERR_PTR(error); -		} -		sb->s_flags |= MS_ACTIVE; +		if (!kobj_ns_current_may_mount(KOBJ_NS_TYPE_NET)) +			return ERR_PTR(-EPERM);  	} -	return dget(sb->s_root); +	ns = kobj_ns_grab_current(KOBJ_NS_TYPE_NET); +	root = kernfs_mount_ns(fs_type, flags, sysfs_root, +				SYSFS_MAGIC, &new_sb, ns); +	if (IS_ERR(root) || !new_sb) +		kobj_ns_drop(KOBJ_NS_TYPE_NET, ns); +	return root;  }  static void sysfs_kill_sb(struct super_block *sb)  { -	struct sysfs_super_info *info = sysfs_info(sb); -	/* Remove the superblock from fs_supers/s_instances -	 * so we can't find it, before freeing sysfs_super_info. -	 */ -	kill_anon_super(sb); -	free_sysfs_super_info(info); +	void *ns = (void *)kernfs_super_ns(sb); + +	kernfs_kill_sb(sb); +	kobj_ns_drop(KOBJ_NS_TYPE_NET, ns);  }  static struct file_system_type sysfs_fs_type = { @@ -165,48 +63,20 @@ static struct file_system_type sysfs_fs_type = {  int __init sysfs_init(void)  { -	int err = -ENOMEM; +	int err; -	sysfs_dir_cachep = kmem_cache_create("sysfs_dir_cache", -					      sizeof(struct sysfs_dirent), -					      0, 0, NULL); -	if (!sysfs_dir_cachep) -		goto out; +	sysfs_root = kernfs_create_root(NULL, KERNFS_ROOT_EXTRA_OPEN_PERM_CHECK, +					NULL); +	if (IS_ERR(sysfs_root)) +		return PTR_ERR(sysfs_root); -	err = sysfs_inode_init(); -	if (err) -		goto out_err; +	sysfs_root_kn = sysfs_root->kn;  	err = register_filesystem(&sysfs_fs_type); -	if (!err) { -		sysfs_mnt = kern_mount(&sysfs_fs_type); -		if (IS_ERR(sysfs_mnt)) { -			printk(KERN_ERR "sysfs: could not mount!\n"); -			err = PTR_ERR(sysfs_mnt); -			sysfs_mnt = NULL; -			unregister_filesystem(&sysfs_fs_type); -			goto out_err; -		} -	} else -		goto out_err; -out: -	return err; -out_err: -	kmem_cache_destroy(sysfs_dir_cachep); -	sysfs_dir_cachep = NULL; -	goto out; -} - -#undef sysfs_get -struct sysfs_dirent *sysfs_get(struct sysfs_dirent *sd) -{ -	return __sysfs_get(sd); -} -EXPORT_SYMBOL_GPL(sysfs_get); +	if (err) { +		kernfs_destroy_root(sysfs_root); +		return err; +	} -#undef sysfs_put -void sysfs_put(struct sysfs_dirent *sd) -{ -	__sysfs_put(sd); +	return 0;  } -EXPORT_SYMBOL_GPL(sysfs_put);  | 
