summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorLiu Bo <bo.li.liu@oracle.com>2013-05-26 09:50:31 -0400
committerJosef Bacik <jbacik@fusionio.com>2013-06-14 11:30:03 -0400
commita96fbc72884fcb0367c6c838357b841b8f10a531 (patch)
tree3a2d3e01260fe038f0b8bc0a114e4dcb4ad816d0 /fs
parentb7394eb91c703a07284501754dc735b3cd0154b7 (diff)
Btrfs: allow file data clone within a file
We did not allow file data clone within the same file because of deadlock issues. However, we now use nested lock to avoid deadlock between the parent directory and the child file. So it's safe to do file clone within the same file when the two ranges are not overlapped. Reviewed-by: David Sterba <dsterba@suse.cz> Signed-off-by: Liu Bo <bo.li.liu@oracle.com> Signed-off-by: Josef Bacik <jbacik@fusionio.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/btrfs/ioctl.c26
1 files changed, 19 insertions, 7 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 015689a158a4..0e17a30f39a2 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -2486,6 +2486,7 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
2486 int ret; 2486 int ret;
2487 u64 len = olen; 2487 u64 len = olen;
2488 u64 bs = root->fs_info->sb->s_blocksize; 2488 u64 bs = root->fs_info->sb->s_blocksize;
2489 int same_inode = 0;
2489 2490
2490 /* 2491 /*
2491 * TODO: 2492 * TODO:
@@ -2522,7 +2523,7 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
2522 2523
2523 ret = -EINVAL; 2524 ret = -EINVAL;
2524 if (src == inode) 2525 if (src == inode)
2525 goto out_fput; 2526 same_inode = 1;
2526 2527
2527 /* the src must be open for reading */ 2528 /* the src must be open for reading */
2528 if (!(src_file.file->f_mode & FMODE_READ)) 2529 if (!(src_file.file->f_mode & FMODE_READ))
@@ -2553,12 +2554,16 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
2553 } 2554 }
2554 path->reada = 2; 2555 path->reada = 2;
2555 2556
2556 if (inode < src) { 2557 if (!same_inode) {
2557 mutex_lock_nested(&inode->i_mutex, I_MUTEX_PARENT); 2558 if (inode < src) {
2558 mutex_lock_nested(&src->i_mutex, I_MUTEX_CHILD); 2559 mutex_lock_nested(&inode->i_mutex, I_MUTEX_PARENT);
2560 mutex_lock_nested(&src->i_mutex, I_MUTEX_CHILD);
2561 } else {
2562 mutex_lock_nested(&src->i_mutex, I_MUTEX_PARENT);
2563 mutex_lock_nested(&inode->i_mutex, I_MUTEX_CHILD);
2564 }
2559 } else { 2565 } else {
2560 mutex_lock_nested(&src->i_mutex, I_MUTEX_PARENT); 2566 mutex_lock(&src->i_mutex);
2561 mutex_lock_nested(&inode->i_mutex, I_MUTEX_CHILD);
2562 } 2567 }
2563 2568
2564 /* determine range to clone */ 2569 /* determine range to clone */
@@ -2576,6 +2581,12 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
2576 !IS_ALIGNED(destoff, bs)) 2581 !IS_ALIGNED(destoff, bs))
2577 goto out_unlock; 2582 goto out_unlock;
2578 2583
2584 /* verify if ranges are overlapped within the same file */
2585 if (same_inode) {
2586 if (destoff + len > off && destoff < off + len)
2587 goto out_unlock;
2588 }
2589
2579 if (destoff > inode->i_size) { 2590 if (destoff > inode->i_size) {
2580 ret = btrfs_cont_expand(inode, inode->i_size, destoff); 2591 ret = btrfs_cont_expand(inode, inode->i_size, destoff);
2581 if (ret) 2592 if (ret)
@@ -2852,7 +2863,8 @@ out:
2852 unlock_extent(&BTRFS_I(src)->io_tree, off, off + len - 1); 2863 unlock_extent(&BTRFS_I(src)->io_tree, off, off + len - 1);
2853out_unlock: 2864out_unlock:
2854 mutex_unlock(&src->i_mutex); 2865 mutex_unlock(&src->i_mutex);
2855 mutex_unlock(&inode->i_mutex); 2866 if (!same_inode)
2867 mutex_unlock(&inode->i_mutex);
2856 vfree(buf); 2868 vfree(buf);
2857 btrfs_free_path(path); 2869 btrfs_free_path(path);
2858out_fput: 2870out_fput: