diff options
Diffstat (limited to 'fs/btrfs/reflink.c')
| -rw-r--r-- | fs/btrfs/reflink.c | 56 | 
1 files changed, 18 insertions, 38 deletions
diff --git a/fs/btrfs/reflink.c b/fs/btrfs/reflink.c index 08d0fb46ceec..d0a3fcecc46a 100644 --- a/fs/btrfs/reflink.c +++ b/fs/btrfs/reflink.c @@ -616,35 +616,6 @@ out:  	return ret;  } -static void btrfs_double_extent_unlock(struct inode *inode1, u64 loff1, -				       struct inode *inode2, u64 loff2, u64 len) -{ -	unlock_extent(&BTRFS_I(inode1)->io_tree, loff1, loff1 + len - 1, NULL); -	unlock_extent(&BTRFS_I(inode2)->io_tree, loff2, loff2 + len - 1, NULL); -} - -static void btrfs_double_extent_lock(struct inode *inode1, u64 loff1, -				     struct inode *inode2, u64 loff2, u64 len) -{ -	u64 range1_end = loff1 + len - 1; -	u64 range2_end = loff2 + len - 1; - -	if (inode1 < inode2) { -		swap(inode1, inode2); -		swap(loff1, loff2); -		swap(range1_end, range2_end); -	} else if (inode1 == inode2 && loff2 < loff1) { -		swap(loff1, loff2); -		swap(range1_end, range2_end); -	} - -	lock_extent(&BTRFS_I(inode1)->io_tree, loff1, range1_end, NULL); -	lock_extent(&BTRFS_I(inode2)->io_tree, loff2, range2_end, NULL); - -	btrfs_assert_inode_range_clean(BTRFS_I(inode1), loff1, range1_end); -	btrfs_assert_inode_range_clean(BTRFS_I(inode2), loff2, range2_end); -} -  static void btrfs_double_mmap_lock(struct inode *inode1, struct inode *inode2)  {  	if (inode1 < inode2) @@ -662,17 +633,21 @@ static void btrfs_double_mmap_unlock(struct inode *inode1, struct inode *inode2)  static int btrfs_extent_same_range(struct inode *src, u64 loff, u64 len,  				   struct inode *dst, u64 dst_loff)  { +	const u64 end = dst_loff + len - 1; +	struct extent_state *cached_state = NULL;  	struct btrfs_fs_info *fs_info = BTRFS_I(src)->root->fs_info;  	const u64 bs = fs_info->sectorsize;  	int ret;  	/* -	 * Lock destination range to serialize with concurrent readahead() and -	 * source range to serialize with relocation. +	 * Lock destination range to serialize with concurrent readahead(), and +	 * we are safe from concurrency with relocation of source extents +	 * because we have already locked the inode's i_mmap_lock in exclusive +	 * mode.  	 */ -	btrfs_double_extent_lock(src, loff, dst, dst_loff, len); +	lock_extent(&BTRFS_I(dst)->io_tree, dst_loff, end, &cached_state);  	ret = btrfs_clone(src, dst, loff, len, ALIGN(len, bs), dst_loff, 1); -	btrfs_double_extent_unlock(src, loff, dst, dst_loff, len); +	unlock_extent(&BTRFS_I(dst)->io_tree, dst_loff, end, &cached_state);  	btrfs_btree_balance_dirty(fs_info); @@ -690,7 +665,7 @@ static int btrfs_extent_same(struct inode *src, u64 loff, u64 olen,  	if (root_dst->send_in_progress) {  		btrfs_warn_rl(root_dst->fs_info,  "cannot deduplicate to root %llu while send operations are using it (%d in progress)", -			      root_dst->root_key.objectid, +			      btrfs_root_id(root_dst),  			      root_dst->send_in_progress);  		spin_unlock(&root_dst->root_item_lock);  		return -EAGAIN; @@ -724,6 +699,7 @@ out:  static noinline int btrfs_clone_files(struct file *file, struct file *file_src,  					u64 off, u64 olen, u64 destoff)  { +	struct extent_state *cached_state = NULL;  	struct inode *inode = file_inode(file);  	struct inode *src = file_inode(file_src);  	struct btrfs_fs_info *fs_info = inode_to_fs_info(inode); @@ -731,6 +707,7 @@ static noinline int btrfs_clone_files(struct file *file, struct file *file_src,  	int wb_ret;  	u64 len = olen;  	u64 bs = fs_info->sectorsize; +	u64 end;  	/*  	 * VFS's generic_remap_file_range_prep() protects us from cloning the @@ -763,12 +740,15 @@ static noinline int btrfs_clone_files(struct file *file, struct file *file_src,  	}  	/* -	 * Lock destination range to serialize with concurrent readahead() and -	 * source range to serialize with relocation. +	 * Lock destination range to serialize with concurrent readahead(), and +	 * we are safe from concurrency with relocation of source extents +	 * because we have already locked the inode's i_mmap_lock in exclusive +	 * mode.  	 */ -	btrfs_double_extent_lock(src, off, inode, destoff, len); +	end = destoff + len - 1; +	lock_extent(&BTRFS_I(inode)->io_tree, destoff, end, &cached_state);  	ret = btrfs_clone(src, inode, off, olen, len, destoff, 0); -	btrfs_double_extent_unlock(src, off, inode, destoff, len); +	unlock_extent(&BTRFS_I(inode)->io_tree, destoff, end, &cached_state);  	/*  	 * We may have copied an inline extent into a page of the destination  |