Skip to content

Commit 2c46382

Browse files
fdmananamasoncl
authored andcommitted
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 <[email protected]> Signed-off-by: Chris Mason <[email protected]>
1 parent c55bfa6 commit 2c46382

File tree

1 file changed

+22
-4
lines changed

1 file changed

+22
-4
lines changed

fs/btrfs/ioctl.c

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3020,7 +3020,7 @@ static int btrfs_clone(struct inode *src, struct inode *inode,
30203020
/* clone data */
30213021
key.objectid = btrfs_ino(src);
30223022
key.type = BTRFS_EXTENT_DATA_KEY;
3023-
key.offset = 0;
3023+
key.offset = off;
30243024

30253025
while (1) {
30263026
/*
@@ -3032,6 +3032,17 @@ static int btrfs_clone(struct inode *src, struct inode *inode,
30323032
0, 0);
30333033
if (ret < 0)
30343034
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+
}
30353046

30363047
nritems = btrfs_header_nritems(path->nodes[0]);
30373048
process_slot:
@@ -3081,10 +3092,16 @@ static int btrfs_clone(struct inode *src, struct inode *inode,
30813092
extent);
30823093
}
30833094

3084-
if (key.offset + datal <= off ||
3085-
key.offset >= off + len - 1) {
3095+
/*
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) {
30863101
path->slots[0]++;
30873102
goto process_slot;
3103+
} else if (key.offset >= off + len) {
3104+
break;
30883105
}
30893106

30903107
size = btrfs_item_size_nr(leaf, slot);
@@ -3291,14 +3308,15 @@ static int btrfs_clone(struct inode *src, struct inode *inode,
32913308
goto out;
32923309
}
32933310
ret = btrfs_end_transaction(trans, root);
3311+
if (new_key.offset + datal >= destoff + len)
3312+
break;
32943313
}
32953314
btrfs_release_path(path);
32963315
key.offset++;
32973316
}
32983317
ret = 0;
32993318

33003319
out:
3301-
btrfs_release_path(path);
33023320
btrfs_free_path(path);
33033321
vfree(buf);
33043322
return ret;

0 commit comments

Comments
 (0)