diff options
Diffstat (limited to 'fs/btrfs/ioctl.c')
| -rw-r--r-- | fs/btrfs/ioctl.c | 68 | 
1 files changed, 21 insertions, 47 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 47aceb494d1d..8a8e29878c34 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -711,39 +711,6 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir,  	if (ret)  		goto fail; -	ret = btrfs_orphan_cleanup(pending_snapshot->snap); -	if (ret) -		goto fail; - -	/* -	 * If orphan cleanup did remove any orphans, it means the tree was -	 * modified and therefore the commit root is not the same as the -	 * current root anymore. This is a problem, because send uses the -	 * commit root and therefore can see inode items that don't exist -	 * in the current root anymore, and for example make calls to -	 * btrfs_iget, which will do tree lookups based on the current root -	 * and not on the commit root. Those lookups will fail, returning a -	 * -ESTALE error, and making send fail with that error. So make sure -	 * a send does not see any orphans we have just removed, and that it -	 * will see the same inodes regardless of whether a transaction -	 * commit happened before it started (meaning that the commit root -	 * will be the same as the current root) or not. -	 */ -	if (readonly && pending_snapshot->snap->node != -	    pending_snapshot->snap->commit_root) { -		trans = btrfs_join_transaction(pending_snapshot->snap); -		if (IS_ERR(trans) && PTR_ERR(trans) != -ENOENT) { -			ret = PTR_ERR(trans); -			goto fail; -		} -		if (!IS_ERR(trans)) { -			ret = btrfs_commit_transaction(trans, -						       pending_snapshot->snap); -			if (ret) -				goto fail; -		} -	} -  	inode = btrfs_lookup_dentry(dentry->d_parent->d_inode, dentry);  	if (IS_ERR(inode)) {  		ret = PTR_ERR(inode); @@ -1052,8 +1019,10 @@ static bool defrag_check_next_extent(struct inode *inode, struct extent_map *em)  		return false;  	next = defrag_lookup_extent(inode, em->start + em->len); -	if (!next || next->block_start >= EXTENT_MAP_LAST_BYTE || -	    (em->block_start + em->block_len == next->block_start)) +	if (!next || next->block_start >= EXTENT_MAP_LAST_BYTE) +		ret = false; +	else if ((em->block_start + em->block_len == next->block_start) && +		 (em->block_len > 128 * 1024 && next->block_len > 128 * 1024))  		ret = false;  	free_extent_map(next); @@ -1088,7 +1057,6 @@ static int should_defrag_range(struct inode *inode, u64 start, int thresh,  	}  	next_mergeable = defrag_check_next_extent(inode, em); -  	/*  	 * we hit a real extent, if it is big or the next extent is not a  	 * real extent, don't bother defragging it @@ -1735,7 +1703,7 @@ static noinline int btrfs_ioctl_snap_create_v2(struct file *file,  	    ~(BTRFS_SUBVOL_CREATE_ASYNC | BTRFS_SUBVOL_RDONLY |  	      BTRFS_SUBVOL_QGROUP_INHERIT)) {  		ret = -EOPNOTSUPP; -		goto out; +		goto free_args;  	}  	if (vol_args->flags & BTRFS_SUBVOL_CREATE_ASYNC) @@ -1745,27 +1713,31 @@ static noinline int btrfs_ioctl_snap_create_v2(struct file *file,  	if (vol_args->flags & BTRFS_SUBVOL_QGROUP_INHERIT) {  		if (vol_args->size > PAGE_CACHE_SIZE) {  			ret = -EINVAL; -			goto out; +			goto free_args;  		}  		inherit = memdup_user(vol_args->qgroup_inherit, vol_args->size);  		if (IS_ERR(inherit)) {  			ret = PTR_ERR(inherit); -			goto out; +			goto free_args;  		}  	}  	ret = btrfs_ioctl_snap_create_transid(file, vol_args->name,  					      vol_args->fd, subvol, ptr,  					      readonly, inherit); +	if (ret) +		goto free_inherit; -	if (ret == 0 && ptr && -	    copy_to_user(arg + -			 offsetof(struct btrfs_ioctl_vol_args_v2, -				  transid), ptr, sizeof(*ptr))) +	if (ptr && copy_to_user(arg + +				offsetof(struct btrfs_ioctl_vol_args_v2, +					transid), +				ptr, sizeof(*ptr)))  		ret = -EFAULT; -out: -	kfree(vol_args); + +free_inherit:  	kfree(inherit); +free_args: +	kfree(vol_args);  	return ret;  } @@ -2685,7 +2657,7 @@ static long btrfs_ioctl_rm_dev(struct file *file, void __user *arg)  	vol_args = memdup_user(arg, sizeof(*vol_args));  	if (IS_ERR(vol_args)) {  		ret = PTR_ERR(vol_args); -		goto out; +		goto err_drop;  	}  	vol_args->name[BTRFS_PATH_NAME_MAX] = '\0'; @@ -2703,6 +2675,7 @@ static long btrfs_ioctl_rm_dev(struct file *file, void __user *arg)  out:  	kfree(vol_args); +err_drop:  	mnt_drop_write_file(file);  	return ret;  } @@ -3527,7 +3500,8 @@ process_slot:  			btrfs_mark_buffer_dirty(leaf);  			btrfs_release_path(path); -			last_dest_end = new_key.offset + datal; +			last_dest_end = ALIGN(new_key.offset + datal, +					      root->sectorsize);  			ret = clone_finish_inode_update(trans, inode,  							last_dest_end,  							destoff, olen);  |