aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark Fasheh <mfasheh@suse.de>2015-06-30 17:42:06 -0400
committerChris Mason <clm@fb.com>2015-08-09 10:34:25 -0400
commit293a8489f300536dc6d996c35a6ebb89aa03bab2 (patch)
treec428134cc3f86ec4e3dd48c413eee15995d5bfc0
parent4a3560c4f3f0f92d3b673944753e3e947e030bc4 (diff)
btrfs: fix clone / extent-same deadlocks
Clone and extent same lock their source and target inodes in opposite order. In addition to this, the range locking in clone doesn't take ordering into account. Fix this by having clone use the same locking helpers as btrfs-extent-same. In addition, I do a small cleanup of the locking helpers, removing a case (both inodes being the same) which was poorly accounted for and never actually used by the callers. Signed-off-by: Mark Fasheh <mfasheh@suse.de> Reviewed-by: David Sterba <dsterba@suse.cz> Signed-off-by: Chris Mason <clm@fb.com>
-rw-r--r--fs/btrfs/ioctl.c34
1 files changed, 8 insertions, 26 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index d1e4cac83311..0adf5422fce9 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -2852,8 +2852,7 @@ static void btrfs_double_inode_lock(struct inode *inode1, struct inode *inode2)
2852 swap(inode1, inode2); 2852 swap(inode1, inode2);
2853 2853
2854 mutex_lock_nested(&inode1->i_mutex, I_MUTEX_PARENT); 2854 mutex_lock_nested(&inode1->i_mutex, I_MUTEX_PARENT);
2855 if (inode1 != inode2) 2855 mutex_lock_nested(&inode2->i_mutex, I_MUTEX_CHILD);
2856 mutex_lock_nested(&inode2->i_mutex, I_MUTEX_CHILD);
2857} 2856}
2858 2857
2859static void btrfs_double_extent_unlock(struct inode *inode1, u64 loff1, 2858static void btrfs_double_extent_unlock(struct inode *inode1, u64 loff1,
@@ -2871,8 +2870,7 @@ static void btrfs_double_extent_lock(struct inode *inode1, u64 loff1,
2871 swap(loff1, loff2); 2870 swap(loff1, loff2);
2872 } 2871 }
2873 lock_extent_range(inode1, loff1, len); 2872 lock_extent_range(inode1, loff1, len);
2874 if (inode1 != inode2) 2873 lock_extent_range(inode2, loff2, len);
2875 lock_extent_range(inode2, loff2, len);
2876} 2874}
2877 2875
2878struct cmp_pages { 2876struct cmp_pages {
@@ -3797,13 +3795,7 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
3797 goto out_fput; 3795 goto out_fput;
3798 3796
3799 if (!same_inode) { 3797 if (!same_inode) {
3800 if (inode < src) { 3798 btrfs_double_inode_lock(src, inode);
3801 mutex_lock_nested(&inode->i_mutex, I_MUTEX_PARENT);
3802 mutex_lock_nested(&src->i_mutex, I_MUTEX_CHILD);
3803 } else {
3804 mutex_lock_nested(&src->i_mutex, I_MUTEX_PARENT);
3805 mutex_lock_nested(&inode->i_mutex, I_MUTEX_CHILD);
3806 }
3807 } else { 3799 } else {
3808 mutex_lock(&src->i_mutex); 3800 mutex_lock(&src->i_mutex);
3809 } 3801 }
@@ -3853,8 +3845,7 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
3853 3845
3854 lock_extent_range(src, lock_start, lock_len); 3846 lock_extent_range(src, lock_start, lock_len);
3855 } else { 3847 } else {
3856 lock_extent_range(src, off, len); 3848 btrfs_double_extent_lock(src, off, inode, destoff, len);
3857 lock_extent_range(inode, destoff, len);
3858 } 3849 }
3859 3850
3860 ret = btrfs_clone(src, inode, off, olen, len, destoff, 0); 3851 ret = btrfs_clone(src, inode, off, olen, len, destoff, 0);
@@ -3865,9 +3856,7 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
3865 3856
3866 unlock_extent(&BTRFS_I(src)->io_tree, lock_start, lock_end); 3857 unlock_extent(&BTRFS_I(src)->io_tree, lock_start, lock_end);
3867 } else { 3858 } else {
3868 unlock_extent(&BTRFS_I(src)->io_tree, off, off + len - 1); 3859 btrfs_double_extent_unlock(src, off, inode, destoff, len);
3869 unlock_extent(&BTRFS_I(inode)->io_tree, destoff,
3870 destoff + len - 1);
3871 } 3860 }
3872 /* 3861 /*
3873 * Truncate page cache pages so that future reads will see the cloned 3862 * Truncate page cache pages so that future reads will see the cloned
@@ -3876,17 +3865,10 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
3876 truncate_inode_pages_range(&inode->i_data, destoff, 3865 truncate_inode_pages_range(&inode->i_data, destoff,
3877 PAGE_CACHE_ALIGN(destoff + len) - 1); 3866 PAGE_CACHE_ALIGN(destoff + len) - 1);
3878out_unlock: 3867out_unlock:
3879 if (!same_inode) { 3868 if (!same_inode)
3880 if (inode < src) { 3869 btrfs_double_inode_unlock(src, inode);
3881 mutex_unlock(&src->i_mutex); 3870 else
3882 mutex_unlock(&inode->i_mutex);
3883 } else {
3884 mutex_unlock(&inode->i_mutex);
3885 mutex_unlock(&src->i_mutex);
3886 }
3887 } else {
3888 mutex_unlock(&src->i_mutex); 3871 mutex_unlock(&src->i_mutex);
3889 }
3890out_fput: 3872out_fput:
3891 fdput(src_file); 3873 fdput(src_file);
3892out_drop_write: 3874out_drop_write: