Skip to content

Commit 1cab137

Browse files
fdmananakdave
authored andcommitted
btrfs: reuse cloned extent buffer during fiemap to avoid re-allocations
During fiemap we may have to visit multiple leaves of the subvolume's inode tree, and each time we are freeing and allocating an extent buffer to use as a clone of each visited leaf. Optimize this by reusing cloned extent buffers, to avoid the freeing and re-allocation both of the extent buffer structure itself and more importantly of the pages attached to the extent buffer. Reviewed-by: Josef Bacik <[email protected]> Signed-off-by: Filipe Manana <[email protected]> Signed-off-by: David Sterba <[email protected]>
1 parent 978b63f commit 1cab137

File tree

1 file changed

+24
-8
lines changed

1 file changed

+24
-8
lines changed

fs/btrfs/extent_io.c

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2752,7 +2752,7 @@ static int emit_last_fiemap_cache(struct fiemap_extent_info *fieinfo,
27522752

27532753
static int fiemap_next_leaf_item(struct btrfs_inode *inode, struct btrfs_path *path)
27542754
{
2755-
struct extent_buffer *clone;
2755+
struct extent_buffer *clone = path->nodes[0];
27562756
struct btrfs_key key;
27572757
int slot;
27582758
int ret;
@@ -2761,29 +2761,45 @@ static int fiemap_next_leaf_item(struct btrfs_inode *inode, struct btrfs_path *p
27612761
if (path->slots[0] < btrfs_header_nritems(path->nodes[0]))
27622762
return 0;
27632763

2764+
/*
2765+
* Add a temporary extra ref to an already cloned extent buffer to
2766+
* prevent btrfs_next_leaf() freeing it, we want to reuse it to avoid
2767+
* the cost of allocating a new one.
2768+
*/
2769+
ASSERT(test_bit(EXTENT_BUFFER_UNMAPPED, &clone->bflags));
2770+
atomic_inc(&clone->refs);
2771+
27642772
ret = btrfs_next_leaf(inode->root, path);
27652773
if (ret != 0)
2766-
return ret;
2774+
goto out;
27672775

27682776
/*
27692777
* Don't bother with cloning if there are no more file extent items for
27702778
* our inode.
27712779
*/
27722780
btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
2773-
if (key.objectid != btrfs_ino(inode) || key.type != BTRFS_EXTENT_DATA_KEY)
2774-
return 1;
2781+
if (key.objectid != btrfs_ino(inode) || key.type != BTRFS_EXTENT_DATA_KEY) {
2782+
ret = 1;
2783+
goto out;
2784+
}
27752785

27762786
/* See the comment at fiemap_search_slot() about why we clone. */
2777-
clone = btrfs_clone_extent_buffer(path->nodes[0]);
2778-
if (!clone)
2779-
return -ENOMEM;
2787+
copy_extent_buffer_full(clone, path->nodes[0]);
2788+
/*
2789+
* Important to preserve the start field, for the optimizations when
2790+
* checking if extents are shared (see extent_fiemap()).
2791+
*/
2792+
clone->start = path->nodes[0]->start;
27802793

27812794
slot = path->slots[0];
27822795
btrfs_release_path(path);
27832796
path->nodes[0] = clone;
27842797
path->slots[0] = slot;
2798+
out:
2799+
if (ret)
2800+
free_extent_buffer(clone);
27852801

2786-
return 0;
2802+
return ret;
27872803
}
27882804

27892805
/*

0 commit comments

Comments
 (0)