Skip to content

Commit

Permalink
btrfs: reuse cloned extent buffer during fiemap to avoid re-allocations
Browse files Browse the repository at this point in the history
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 <josef@toxicpanda.com>
Signed-off-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
  • Loading branch information
fdmanana authored and kdave committed Mar 5, 2024
1 parent 978b63f commit 1cab137
Showing 1 changed file with 24 additions and 8 deletions.
32 changes: 24 additions & 8 deletions fs/btrfs/extent_io.c
Original file line number Diff line number Diff line change
Expand Up @@ -2752,7 +2752,7 @@ static int emit_last_fiemap_cache(struct fiemap_extent_info *fieinfo,

static int fiemap_next_leaf_item(struct btrfs_inode *inode, struct btrfs_path *path)
{
struct extent_buffer *clone;
struct extent_buffer *clone = path->nodes[0];
struct btrfs_key key;
int slot;
int ret;
Expand All @@ -2761,29 +2761,45 @@ static int fiemap_next_leaf_item(struct btrfs_inode *inode, struct btrfs_path *p
if (path->slots[0] < btrfs_header_nritems(path->nodes[0]))
return 0;

/*
* Add a temporary extra ref to an already cloned extent buffer to
* prevent btrfs_next_leaf() freeing it, we want to reuse it to avoid
* the cost of allocating a new one.
*/
ASSERT(test_bit(EXTENT_BUFFER_UNMAPPED, &clone->bflags));
atomic_inc(&clone->refs);

ret = btrfs_next_leaf(inode->root, path);
if (ret != 0)
return ret;
goto out;

/*
* Don't bother with cloning if there are no more file extent items for
* our inode.
*/
btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
if (key.objectid != btrfs_ino(inode) || key.type != BTRFS_EXTENT_DATA_KEY)
return 1;
if (key.objectid != btrfs_ino(inode) || key.type != BTRFS_EXTENT_DATA_KEY) {
ret = 1;
goto out;
}

/* See the comment at fiemap_search_slot() about why we clone. */
clone = btrfs_clone_extent_buffer(path->nodes[0]);
if (!clone)
return -ENOMEM;
copy_extent_buffer_full(clone, path->nodes[0]);
/*
* Important to preserve the start field, for the optimizations when
* checking if extents are shared (see extent_fiemap()).
*/
clone->start = path->nodes[0]->start;

slot = path->slots[0];
btrfs_release_path(path);
path->nodes[0] = clone;
path->slots[0] = slot;
out:
if (ret)
free_extent_buffer(clone);

return 0;
return ret;
}

/*
Expand Down

0 comments on commit 1cab137

Please sign in to comment.