diff options
Diffstat (limited to 'fs/btrfs/ioctl.c')
| -rw-r--r-- | fs/btrfs/ioctl.c | 120 | 
1 files changed, 96 insertions, 24 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 338f2597bf7..059546aa8fd 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -42,12 +42,12 @@  #include <linux/slab.h>  #include <linux/blkdev.h>  #include <linux/uuid.h> +#include <linux/btrfs.h>  #include "compat.h"  #include "ctree.h"  #include "disk-io.h"  #include "transaction.h"  #include "btrfs_inode.h" -#include "ioctl.h"  #include "print-tree.h"  #include "volumes.h"  #include "locking.h" @@ -367,7 +367,7 @@ static noinline int create_subvol(struct btrfs_root *root,  				  struct dentry *dentry,  				  char *name, int namelen,  				  u64 *async_transid, -				  struct btrfs_qgroup_inherit **inherit) +				  struct btrfs_qgroup_inherit *inherit)  {  	struct btrfs_trans_handle *trans;  	struct btrfs_key key; @@ -401,8 +401,7 @@ static noinline int create_subvol(struct btrfs_root *root,  	if (IS_ERR(trans))  		return PTR_ERR(trans); -	ret = btrfs_qgroup_inherit(trans, root->fs_info, 0, objectid, -				   inherit ? *inherit : NULL); +	ret = btrfs_qgroup_inherit(trans, root->fs_info, 0, objectid, inherit);  	if (ret)  		goto fail; @@ -533,7 +532,7 @@ fail:  static int create_snapshot(struct btrfs_root *root, struct dentry *dentry,  			   char *name, int namelen, u64 *async_transid, -			   bool readonly, struct btrfs_qgroup_inherit **inherit) +			   bool readonly, struct btrfs_qgroup_inherit *inherit)  {  	struct inode *inode;  	struct btrfs_pending_snapshot *pending_snapshot; @@ -552,10 +551,7 @@ static int create_snapshot(struct btrfs_root *root, struct dentry *dentry,  	pending_snapshot->dentry = dentry;  	pending_snapshot->root = root;  	pending_snapshot->readonly = readonly; -	if (inherit) { -		pending_snapshot->inherit = *inherit; -		*inherit = NULL;	/* take responsibility to free it */ -	} +	pending_snapshot->inherit = inherit;  	trans = btrfs_start_transaction(root->fs_info->extent_root, 6);  	if (IS_ERR(trans)) { @@ -695,7 +691,7 @@ static noinline int btrfs_mksubvol(struct path *parent,  				   char *name, int namelen,  				   struct btrfs_root *snap_src,  				   u64 *async_transid, bool readonly, -				   struct btrfs_qgroup_inherit **inherit) +				   struct btrfs_qgroup_inherit *inherit)  {  	struct inode *dir  = parent->dentry->d_inode;  	struct dentry *dentry; @@ -818,7 +814,7 @@ static int find_new_extents(struct btrfs_root *root,  	while(1) {  		ret = btrfs_search_forward(root, &min_key, &max_key, -					   path, 0, newer_than); +					   path, newer_than);  		if (ret != 0)  			goto none;  		if (min_key.objectid != ino) @@ -1206,6 +1202,12 @@ int btrfs_defrag_file(struct inode *inode, struct file *file,  		if (!(inode->i_sb->s_flags & MS_ACTIVE))  			break; +		if (btrfs_defrag_cancelled(root->fs_info)) { +			printk(KERN_DEBUG "btrfs: defrag_file cancelled\n"); +			ret = -EAGAIN; +			break; +		} +  		if (!should_defrag_range(inode, (u64)i << PAGE_CACHE_SHIFT,  					 extent_thresh, &last_len, &skip,  					 &defrag_end, range->flags & @@ -1329,9 +1331,6 @@ static noinline int btrfs_ioctl_resize(struct file *file,  	int ret = 0;  	int mod = 0; -	if (root->fs_info->sb->s_flags & MS_RDONLY) -		return -EROFS; -  	if (!capable(CAP_SYS_ADMIN))  		return -EPERM; @@ -1363,6 +1362,10 @@ static noinline int btrfs_ioctl_resize(struct file *file,  		*devstr = '\0';  		devstr = vol_args->name;  		devid = simple_strtoull(devstr, &end, 10); +		if (!devid) { +			ret = -EINVAL; +			goto out_free; +		}  		printk(KERN_INFO "btrfs: resizing devid %llu\n",  		       (unsigned long long)devid);  	} @@ -1371,7 +1374,7 @@ static noinline int btrfs_ioctl_resize(struct file *file,  	if (!device) {  		printk(KERN_INFO "btrfs: resizer unable to find device %llu\n",  		       (unsigned long long)devid); -		ret = -EINVAL; +		ret = -ENODEV;  		goto out_free;  	} @@ -1379,7 +1382,7 @@ static noinline int btrfs_ioctl_resize(struct file *file,  		printk(KERN_INFO "btrfs: resizer unable to apply on "  		       "readonly device %llu\n",  		       (unsigned long long)devid); -		ret = -EINVAL; +		ret = -EPERM;  		goto out_free;  	} @@ -1401,7 +1404,7 @@ static noinline int btrfs_ioctl_resize(struct file *file,  	}  	if (device->is_tgtdev_for_dev_replace) { -		ret = -EINVAL; +		ret = -EPERM;  		goto out_free;  	} @@ -1457,7 +1460,7 @@ out:  static noinline int btrfs_ioctl_snap_create_transid(struct file *file,  				char *name, unsigned long fd, int subvol,  				u64 *transid, bool readonly, -				struct btrfs_qgroup_inherit **inherit) +				struct btrfs_qgroup_inherit *inherit)  {  	int namelen;  	int ret = 0; @@ -1566,7 +1569,7 @@ static noinline int btrfs_ioctl_snap_create_v2(struct file *file,  	ret = btrfs_ioctl_snap_create_transid(file, vol_args->name,  					      vol_args->fd, subvol, ptr, -					      readonly, &inherit); +					      readonly, inherit);  	if (ret == 0 && ptr &&  	    copy_to_user(arg + @@ -1863,7 +1866,7 @@ static noinline int search_ioctl(struct inode *inode,  	path->keep_locks = 1;  	while(1) { -		ret = btrfs_search_forward(root, &key, &max_key, path, 0, +		ret = btrfs_search_forward(root, &key, &max_key, path,  					   sk->min_transid);  		if (ret != 0) {  			if (ret > 0) @@ -2171,6 +2174,12 @@ out_unlock:  		shrink_dcache_sb(root->fs_info->sb);  		btrfs_invalidate_inodes(dest);  		d_delete(dentry); + +		/* the last ref */ +		if (dest->cache_inode) { +			iput(dest->cache_inode); +			dest->cache_inode = NULL; +		}  	}  out_dput:  	dput(dentry); @@ -2211,10 +2220,10 @@ static int btrfs_ioctl_defrag(struct file *file, void __user *argp)  			ret = -EPERM;  			goto out;  		} -		ret = btrfs_defrag_root(root, 0); +		ret = btrfs_defrag_root(root);  		if (ret)  			goto out; -		ret = btrfs_defrag_root(root->fs_info->extent_root, 0); +		ret = btrfs_defrag_root(root->fs_info->extent_root);  		break;  	case S_IFREG:  		if (!(file->f_mode & FMODE_WRITE)) { @@ -3111,7 +3120,7 @@ static noinline long btrfs_ioctl_start_sync(struct btrfs_root *root,  	u64 transid;  	int ret; -	trans = btrfs_attach_transaction(root); +	trans = btrfs_attach_transaction_barrier(root);  	if (IS_ERR(trans)) {  		if (PTR_ERR(trans) != -ENOENT)  			return PTR_ERR(trans); @@ -3289,7 +3298,7 @@ static long btrfs_ioctl_ino_to_path(struct btrfs_root *root, void __user *arg)  	struct inode_fs_paths *ipath = NULL;  	struct btrfs_path *path; -	if (!capable(CAP_SYS_ADMIN)) +	if (!capable(CAP_DAC_READ_SEARCH))  		return -EPERM;  	path = btrfs_alloc_path(); @@ -3914,6 +3923,65 @@ out:  	return ret;  } +static int btrfs_ioctl_get_fslabel(struct file *file, void __user *arg) +{ +	struct btrfs_root *root = BTRFS_I(fdentry(file)->d_inode)->root; +	const char *label = root->fs_info->super_copy->label; +	size_t len = strnlen(label, BTRFS_LABEL_SIZE); +	int ret; + +	if (len == BTRFS_LABEL_SIZE) { +		pr_warn("btrfs: label is too long, return the first %zu bytes\n", +			--len); +	} + +	mutex_lock(&root->fs_info->volume_mutex); +	ret = copy_to_user(arg, label, len); +	mutex_unlock(&root->fs_info->volume_mutex); + +	return ret ? -EFAULT : 0; +} + +static int btrfs_ioctl_set_fslabel(struct file *file, void __user *arg) +{ +	struct btrfs_root *root = BTRFS_I(fdentry(file)->d_inode)->root; +	struct btrfs_super_block *super_block = root->fs_info->super_copy; +	struct btrfs_trans_handle *trans; +	char label[BTRFS_LABEL_SIZE]; +	int ret; + +	if (!capable(CAP_SYS_ADMIN)) +		return -EPERM; + +	if (copy_from_user(label, arg, sizeof(label))) +		return -EFAULT; + +	if (strnlen(label, BTRFS_LABEL_SIZE) == BTRFS_LABEL_SIZE) { +		pr_err("btrfs: unable to set label with more than %d bytes\n", +		       BTRFS_LABEL_SIZE - 1); +		return -EINVAL; +	} + +	ret = mnt_want_write_file(file); +	if (ret) +		return ret; + +	mutex_lock(&root->fs_info->volume_mutex); +	trans = btrfs_start_transaction(root, 0); +	if (IS_ERR(trans)) { +		ret = PTR_ERR(trans); +		goto out_unlock; +	} + +	strcpy(super_block->label, label); +	ret = btrfs_end_transaction(trans, root); + +out_unlock: +	mutex_unlock(&root->fs_info->volume_mutex); +	mnt_drop_write_file(file); +	return ret; +} +  long btrfs_ioctl(struct file *file, unsigned int  		cmd, unsigned long arg)  { @@ -4014,6 +4082,10 @@ long btrfs_ioctl(struct file *file, unsigned int  		return btrfs_ioctl_qgroup_limit(file, argp);  	case BTRFS_IOC_DEV_REPLACE:  		return btrfs_ioctl_dev_replace(root, argp); +	case BTRFS_IOC_GET_FSLABEL: +		return btrfs_ioctl_get_fslabel(file, argp); +	case BTRFS_IOC_SET_FSLABEL: +		return btrfs_ioctl_set_fslabel(file, argp);  	}  	return -ENOTTY;  |