summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFilipe Manana <fdmanana@suse.com>2026-01-20 11:55:14 +0000
committerDavid Sterba <dsterba@suse.com>2026-02-03 07:56:18 +0100
commite46a9f84bfe8f3662b3ae8ad183d6067888b5469 (patch)
tree6fdea02e005ed19c7a225bc31783e20dadfa798b
parent17078525e5be48381a35068535feb9adb36635f3 (diff)
btrfs: allocate path on stack in load_block_group_size_class()
Instead of allocating and freeing a path in every iteration of load_block_group_size_class(), through its helper function sample_block_group_extent_item(), allocate the path in the former and pass it to the later. The path is allocated on stack since it's short and we are in a workqueue context so there's not much stack usage. Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com> Reviewed-by: Qu Wenruo <wqu@suse.com> Signed-off-by: Filipe Manana <fdmanana@suse.com> Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
-rw-r--r--fs/btrfs/block-group.c32
1 files changed, 19 insertions, 13 deletions
diff --git a/fs/btrfs/block-group.c b/fs/btrfs/block-group.c
index 20dd4a3d9961..fe42e0e2b597 100644
--- a/fs/btrfs/block-group.c
+++ b/fs/btrfs/block-group.c
@@ -579,24 +579,24 @@ int btrfs_add_new_free_space(struct btrfs_block_group *block_group, u64 start,
* @index: the integral step through the block group to grab from
* @max_index: the granularity of the sampling
* @key: return value parameter for the item we find
+ * @path: path to use for searching in the extent tree
*
* Pre-conditions on indices:
* 0 <= index <= max_index
* 0 < max_index
*
- * Returns: 0 on success, 1 if the search didn't yield a useful item, negative
- * error code on error.
+ * Returns: 0 on success, 1 if the search didn't yield a useful item.
*/
static int sample_block_group_extent_item(struct btrfs_caching_control *caching_ctl,
struct btrfs_block_group *block_group,
int index, int max_index,
- struct btrfs_key *found_key)
+ struct btrfs_key *found_key,
+ struct btrfs_path *path)
{
struct btrfs_fs_info *fs_info = block_group->fs_info;
struct btrfs_root *extent_root;
u64 search_offset;
const u64 search_end = btrfs_block_group_end(block_group);
- BTRFS_PATH_AUTO_FREE(path);
struct btrfs_key search_key;
int ret = 0;
@@ -606,17 +606,9 @@ static int sample_block_group_extent_item(struct btrfs_caching_control *caching_
lockdep_assert_held(&caching_ctl->mutex);
lockdep_assert_held_read(&fs_info->commit_root_sem);
- path = btrfs_alloc_path();
- if (!path)
- return -ENOMEM;
-
extent_root = btrfs_extent_root(fs_info, max_t(u64, block_group->start,
BTRFS_SUPER_INFO_OFFSET));
- path->skip_locking = true;
- path->search_commit_root = true;
- path->reada = READA_FORWARD;
-
search_offset = index * div_u64(block_group->length, max_index);
search_key.objectid = block_group->start + search_offset;
search_key.type = BTRFS_EXTENT_ITEM_KEY;
@@ -679,23 +671,37 @@ static int sample_block_group_extent_item(struct btrfs_caching_control *caching_
static void load_block_group_size_class(struct btrfs_caching_control *caching_ctl,
struct btrfs_block_group *block_group)
{
+ BTRFS_PATH_AUTO_RELEASE(path);
struct btrfs_fs_info *fs_info = block_group->fs_info;
struct btrfs_key key;
int i;
u64 min_size = block_group->length;
enum btrfs_block_group_size_class size_class = BTRFS_BG_SZ_NONE;
+ /*
+ * Since we run in workqueue context, we allocate the path on stack to
+ * avoid memory allocation failure, as the stack in a work queue task
+ * is not deep.
+ */
+ ASSERT(current_work() == &caching_ctl->work.normal_work);
+
if (!btrfs_block_group_should_use_size_class(block_group))
return;
+ path.skip_locking = true;
+ path.search_commit_root = true;
+ path.reada = READA_FORWARD;
+
lockdep_assert_held(&caching_ctl->mutex);
lockdep_assert_held_read(&fs_info->commit_root_sem);
for (i = 0; i < 5; ++i) {
int ret;
- ret = sample_block_group_extent_item(caching_ctl, block_group, i, 5, &key);
+ ret = sample_block_group_extent_item(caching_ctl, block_group,
+ i, 5, &key, &path);
if (ret < 0)
return;
+ btrfs_release_path(&path);
if (ret > 0)
continue;
min_size = min_t(u64, min_size, key.offset);