aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/btrfs/ioctl.c26
1 files changed, 22 insertions, 4 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 38f2169b73a4..f0b4237cedfc 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -3020,7 +3020,7 @@ static int btrfs_clone(struct inode *src, struct inode *inode,
3020 /* clone data */ 3020 /* clone data */
3021 key.objectid = btrfs_ino(src); 3021 key.objectid = btrfs_ino(src);
3022 key.type = BTRFS_EXTENT_DATA_KEY; 3022 key.type = BTRFS_EXTENT_DATA_KEY;
3023 key.offset = 0; 3023 key.offset = off;
3024 3024
3025 while (1) { 3025 while (1) {
3026 /* 3026 /*
@@ -3032,6 +3032,17 @@ static int btrfs_clone(struct inode *src, struct inode *inode,
3032 0, 0); 3032 0, 0);
3033 if (ret < 0) 3033 if (ret < 0)
3034 goto out; 3034 goto out;
3035 /*
3036 * First search, if no extent item that starts at offset off was
3037 * found but the previous item is an extent item, it's possible
3038 * it might overlap our target range, therefore process it.
3039 */
3040 if (key.offset == off && ret > 0 && path->slots[0] > 0) {
3041 btrfs_item_key_to_cpu(path->nodes[0], &key,
3042 path->slots[0] - 1);
3043 if (key.type == BTRFS_EXTENT_DATA_KEY)
3044 path->slots[0]--;
3045 }
3035 3046
3036 nritems = btrfs_header_nritems(path->nodes[0]); 3047 nritems = btrfs_header_nritems(path->nodes[0]);
3037process_slot: 3048process_slot:
@@ -3081,10 +3092,16 @@ process_slot:
3081 extent); 3092 extent);
3082 } 3093 }
3083 3094
3084 if (key.offset + datal <= off || 3095 /*
3085 key.offset >= off + len - 1) { 3096 * The first search might have left us at an extent
3097 * item that ends before our target range's start, can
3098 * happen if we have holes and NO_HOLES feature enabled.
3099 */
3100 if (key.offset + datal <= off) {
3086 path->slots[0]++; 3101 path->slots[0]++;
3087 goto process_slot; 3102 goto process_slot;
3103 } else if (key.offset >= off + len) {
3104 break;
3088 } 3105 }
3089 3106
3090 size = btrfs_item_size_nr(leaf, slot); 3107 size = btrfs_item_size_nr(leaf, slot);
@@ -3291,6 +3308,8 @@ process_slot:
3291 goto out; 3308 goto out;
3292 } 3309 }
3293 ret = btrfs_end_transaction(trans, root); 3310 ret = btrfs_end_transaction(trans, root);
3311 if (new_key.offset + datal >= destoff + len)
3312 break;
3294 } 3313 }
3295 btrfs_release_path(path); 3314 btrfs_release_path(path);
3296 key.offset++; 3315 key.offset++;
@@ -3298,7 +3317,6 @@ process_slot:
3298 ret = 0; 3317 ret = 0;
3299 3318
3300out: 3319out:
3301 btrfs_release_path(path);
3302 btrfs_free_path(path); 3320 btrfs_free_path(path);
3303 vfree(buf); 3321 vfree(buf);
3304 return ret; 3322 return ret;