diff options
Diffstat (limited to 'fs/btrfs/ioctl.c')
| -rw-r--r-- | fs/btrfs/ioctl.c | 40 | 
1 files changed, 26 insertions, 14 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index a1ee0b775e65..12ae31e1813e 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -704,11 +704,17 @@ static noinline int create_subvol(struct inode *dir,  	btrfs_i_size_write(BTRFS_I(dir), dir->i_size + namelen * 2);  	ret = btrfs_update_inode(trans, root, dir); -	BUG_ON(ret); +	if (ret) { +		btrfs_abort_transaction(trans, ret); +		goto fail; +	}  	ret = btrfs_add_root_ref(trans, objectid, root->root_key.objectid,  				 btrfs_ino(BTRFS_I(dir)), index, name, namelen); -	BUG_ON(ret); +	if (ret) { +		btrfs_abort_transaction(trans, ret); +		goto fail; +	}  	ret = btrfs_uuid_tree_add(trans, root_item->uuid,  				  BTRFS_UUID_KEY_SUBVOL, objectid); @@ -3720,24 +3726,18 @@ process_slot:  	ret = 0;  	if (last_dest_end < destoff + len) { -		struct btrfs_clone_extent_info clone_info = { 0 };  		/* -		 * We have an implicit hole (NO_HOLES feature is enabled) that -		 * fully or partially overlaps our cloning range at its end. +		 * We have an implicit hole that fully or partially overlaps our +		 * cloning range at its end. This means that we either have the +		 * NO_HOLES feature enabled or the implicit hole happened due to +		 * mixing buffered and direct IO writes against this file.  		 */  		btrfs_release_path(path);  		path->leave_spinning = 0; -		/* -		 * We are dealing with a hole and our clone_info already has a -		 * disk_offset of 0, we only need to fill the data length and -		 * file offset. -		 */ -		clone_info.data_len = destoff + len - last_dest_end; -		clone_info.file_offset = last_dest_end;  		ret = btrfs_punch_hole_range(inode, path,  					     last_dest_end, destoff + len - 1, -					     &clone_info, &trans); +					     NULL, &trans);  		if (ret)  			goto out; @@ -4252,7 +4252,19 @@ static long btrfs_ioctl_scrub(struct file *file, void __user *arg)  			      &sa->progress, sa->flags & BTRFS_SCRUB_READONLY,  			      0); -	if (ret == 0 && copy_to_user(arg, sa, sizeof(*sa))) +	/* +	 * Copy scrub args to user space even if btrfs_scrub_dev() returned an +	 * error. This is important as it allows user space to know how much +	 * progress scrub has done. For example, if scrub is canceled we get +	 * -ECANCELED from btrfs_scrub_dev() and return that error back to user +	 * space. Later user space can inspect the progress from the structure +	 * btrfs_ioctl_scrub_args and resume scrub from where it left off +	 * previously (btrfs-progs does this). +	 * If we fail to copy the btrfs_ioctl_scrub_args structure to user space +	 * then return -EFAULT to signal the structure was not copied or it may +	 * be corrupt and unreliable due to a partial copy. +	 */ +	if (copy_to_user(arg, sa, sizeof(*sa)))  		ret = -EFAULT;  	if (!(sa->flags & BTRFS_SCRUB_READONLY))  | 

