aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFilipe Manana <fdmanana@gmail.com>2014-05-30 21:31:05 -0400
committerChris Mason <clm@fb.com>2014-06-09 20:21:04 -0400
commit2c463823cb897a8e1758518c911646f5605cdd82 (patch)
tree65f95634ccd85b562325e1134ce16180cb179c32
parentc55bfa67e94e22ec0449fe7c55b3ef20fbe13348 (diff)
Btrfs: avoid visiting all extent items when cloning a range
When cloning a range of a file, we were visiting all the extent items in the btree that belong to our source inode. We don't need to visit those extent items that don't overlap the range we are cloning, as doing so only makes us waste time and do unnecessary btree navigations (btrfs_next_leaf) for inodes that have a large number of file extent items in the btree. Signed-off-by: Filipe David Borba Manana <fdmanana@gmail.com> Signed-off-by: Chris Mason <clm@fb.com>
-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;