diff options
Diffstat (limited to 'fs/btrfs/super.c')
| -rw-r--r-- | fs/btrfs/super.c | 87 | 
1 files changed, 33 insertions, 54 deletions
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 57080dffdfc..17ee7fc5e64 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -197,7 +197,7 @@ static match_table_t tokens = {  	{Opt_subvolrootid, "subvolrootid=%d"},  	{Opt_defrag, "autodefrag"},  	{Opt_inode_cache, "inode_cache"}, -	{Opt_no_space_cache, "no_space_cache"}, +	{Opt_no_space_cache, "nospace_cache"},  	{Opt_recovery, "recovery"},  	{Opt_err, NULL},  }; @@ -448,6 +448,7 @@ static int btrfs_parse_early_options(const char *options, fmode_t flags,  		token = match_token(p, tokens, args);  		switch (token) {  		case Opt_subvol: +			kfree(*subvol_name);  			*subvol_name = match_strdup(&args[0]);  			break;  		case Opt_subvolid: @@ -710,7 +711,7 @@ static int btrfs_show_options(struct seq_file *seq, struct vfsmount *vfs)  	if (btrfs_test_opt(root, SPACE_CACHE))  		seq_puts(seq, ",space_cache");  	else -		seq_puts(seq, ",no_space_cache"); +		seq_puts(seq, ",nospace_cache");  	if (btrfs_test_opt(root, CLEAR_CACHE))  		seq_puts(seq, ",clear_cache");  	if (btrfs_test_opt(root, USER_SUBVOL_RM_ALLOWED)) @@ -824,13 +825,9 @@ static char *setup_root_args(char *args)  static struct dentry *mount_subvol(const char *subvol_name, int flags,  				   const char *device_name, char *data)  { -	struct super_block *s;  	struct dentry *root;  	struct vfsmount *mnt; -	struct mnt_namespace *ns_private;  	char *newargs; -	struct path path; -	int error;  	newargs = setup_root_args(data);  	if (!newargs) @@ -841,39 +838,17 @@ static struct dentry *mount_subvol(const char *subvol_name, int flags,  	if (IS_ERR(mnt))  		return ERR_CAST(mnt); -	ns_private = create_mnt_ns(mnt); -	if (IS_ERR(ns_private)) { -		mntput(mnt); -		return ERR_CAST(ns_private); -	} - -	/* -	 * This will trigger the automount of the subvol so we can just -	 * drop the mnt we have here and return the dentry that we -	 * found. -	 */ -	error = vfs_path_lookup(mnt->mnt_root, mnt, subvol_name, -				LOOKUP_FOLLOW, &path); -	put_mnt_ns(ns_private); -	if (error) -		return ERR_PTR(error); +	root = mount_subtree(mnt, subvol_name); -	if (!is_subvolume_inode(path.dentry->d_inode)) { -		path_put(&path); -		mntput(mnt); -		error = -EINVAL; +	if (!IS_ERR(root) && !is_subvolume_inode(root->d_inode)) { +		struct super_block *s = root->d_sb; +		dput(root); +		root = ERR_PTR(-EINVAL); +		deactivate_locked_super(s);  		printk(KERN_ERR "btrfs: '%s' is not a valid subvolume\n",  				subvol_name); -		return ERR_PTR(-EINVAL);  	} -	/* Get a ref to the sb and the dentry we found and return it */ -	s = path.mnt->mnt_sb; -	atomic_inc(&s->s_active); -	root = dget(path.dentry); -	path_put(&path); -	down_write(&s->s_umount); -  	return root;  } @@ -890,7 +865,6 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,  	struct super_block *s;  	struct dentry *root;  	struct btrfs_fs_devices *fs_devices = NULL; -	struct btrfs_root *tree_root = NULL;  	struct btrfs_fs_info *fs_info = NULL;  	fmode_t mode = FMODE_READ;  	char *subvol_name = NULL; @@ -904,8 +878,10 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,  	error = btrfs_parse_early_options(data, mode, fs_type,  					  &subvol_name, &subvol_objectid,  					  &subvol_rootid, &fs_devices); -	if (error) +	if (error) { +		kfree(subvol_name);  		return ERR_PTR(error); +	}  	if (subvol_name) {  		root = mount_subvol(subvol_name, flags, device_name, data); @@ -917,15 +893,6 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,  	if (error)  		return ERR_PTR(error); -	error = btrfs_open_devices(fs_devices, mode, fs_type); -	if (error) -		return ERR_PTR(error); - -	if (!(flags & MS_RDONLY) && fs_devices->rw_devices == 0) { -		error = -EACCES; -		goto error_close_devices; -	} -  	/*  	 * Setup a dummy root and fs_info for test/set super.  This is because  	 * we don't actually fill this stuff out until open_ctree, but we need @@ -933,24 +900,36 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,  	 * then open_ctree will properly initialize everything later.  	 */  	fs_info = kzalloc(sizeof(struct btrfs_fs_info), GFP_NOFS); -	tree_root = kzalloc(sizeof(struct btrfs_root), GFP_NOFS); -	if (!fs_info || !tree_root) { +	if (!fs_info) +		return ERR_PTR(-ENOMEM); + +	fs_info->tree_root = kzalloc(sizeof(struct btrfs_root), GFP_NOFS); +	if (!fs_info->tree_root) {  		error = -ENOMEM; -		goto error_close_devices; +		goto error_fs_info;  	} -	fs_info->tree_root = tree_root; +	fs_info->tree_root->fs_info = fs_info;  	fs_info->fs_devices = fs_devices; -	tree_root->fs_info = fs_info;  	fs_info->super_copy = kzalloc(BTRFS_SUPER_INFO_SIZE, GFP_NOFS);  	fs_info->super_for_commit = kzalloc(BTRFS_SUPER_INFO_SIZE, GFP_NOFS);  	if (!fs_info->super_copy || !fs_info->super_for_commit) {  		error = -ENOMEM; +		goto error_fs_info; +	} + +	error = btrfs_open_devices(fs_devices, mode, fs_type); +	if (error) +		goto error_fs_info; + +	if (!(flags & MS_RDONLY) && fs_devices->rw_devices == 0) { +		error = -EACCES;  		goto error_close_devices;  	}  	bdev = fs_devices->latest_bdev; -	s = sget(fs_type, btrfs_test_super, btrfs_set_super, tree_root); +	s = sget(fs_type, btrfs_test_super, btrfs_set_super, +		 fs_info->tree_root);  	if (IS_ERR(s)) {  		error = PTR_ERR(s);  		goto error_close_devices; @@ -959,12 +938,12 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,  	if (s->s_root) {  		if ((flags ^ s->s_flags) & MS_RDONLY) {  			deactivate_locked_super(s); -			return ERR_PTR(-EBUSY); +			error = -EBUSY; +			goto error_close_devices;  		}  		btrfs_close_devices(fs_devices);  		free_fs_info(fs_info); -		kfree(tree_root);  	} else {  		char b[BDEVNAME_SIZE]; @@ -991,8 +970,8 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,  error_close_devices:  	btrfs_close_devices(fs_devices); +error_fs_info:  	free_fs_info(fs_info); -	kfree(tree_root);  	return ERR_PTR(error);  }  |