btrfs: reuse roots ulist on each leaf iteration for iterate_extent_inodes()
authorFilipe Manana <fdmanana@suse.com>
Tue, 1 Nov 2022 16:15:48 +0000 (16:15 +0000)
committerDavid Sterba <dsterba@suse.com>
Mon, 5 Dec 2022 17:00:50 +0000 (18:00 +0100)
At iterate_extent_inodes() we collect a ulist of leaves for a given extent
with a call to btrfs_find_all_leafs() and then we enter a loop where we
iterate over all the collected leaves. Each iteration of that loop does a
call to btrfs_find_all_roots_safe(), to determine all roots from which a
leaf is accessible, and that results in allocating and releasing a ulist
to store the root IDs.

Instead of allocating and releasing the roots ulist on every iteration,
allocate a ulist before entering the loop and keep using it on each
iteration, reinitializing the ulist at the end of each iteration.

Signed-off-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/backref.c

index a1a00a7..dc276ce 100644 (file)
@@ -1674,32 +1674,36 @@ int btrfs_find_all_leafs(struct btrfs_backref_walk_ctx *ctx)
  * the current while iterating. The process stops when we reach the end of the
  * list.
  *
- * Found roots are added to @ctx->roots, which is allocated by this function and
- * @ctx->roots should be NULL when calling this function. This function also
- * requires @ctx->refs to be NULL, as it uses it for allocating a ulist to do
- * temporary work, and frees it before returning.
+ * Found roots are added to @ctx->roots, which is allocated by this function if
+ * it points to NULL, in which case the caller is responsible for freeing it
+ * after it's not needed anymore.
+ * This function requires @ctx->refs to be NULL, as it uses it for allocating a
+ * ulist to do temporary work, and frees it before returning.
  *
- * Returns 0 on success, < 0 on error. On error @ctx->roots is always NULL.
+ * Returns 0 on success, < 0 on error.
  */
 static int btrfs_find_all_roots_safe(struct btrfs_backref_walk_ctx *ctx)
 {
        const u64 orig_bytenr = ctx->bytenr;
        const bool orig_ignore_extent_item_pos = ctx->ignore_extent_item_pos;
+       bool roots_ulist_allocated = false;
        struct ulist_iterator uiter;
        int ret = 0;
 
        ASSERT(ctx->refs == NULL);
-       ASSERT(ctx->roots == NULL);
 
        ctx->refs = ulist_alloc(GFP_NOFS);
        if (!ctx->refs)
                return -ENOMEM;
 
-       ctx->roots = ulist_alloc(GFP_NOFS);
        if (!ctx->roots) {
-               ulist_free(ctx->refs);
-               ctx->refs = NULL;
-               return -ENOMEM;
+               ctx->roots = ulist_alloc(GFP_NOFS);
+               if (!ctx->roots) {
+                       ulist_free(ctx->refs);
+                       ctx->refs = NULL;
+                       return -ENOMEM;
+               }
+               roots_ulist_allocated = true;
        }
 
        ctx->ignore_extent_item_pos = true;
@@ -1710,8 +1714,10 @@ static int btrfs_find_all_roots_safe(struct btrfs_backref_walk_ctx *ctx)
 
                ret = find_parent_nodes(ctx, NULL);
                if (ret < 0 && ret != -ENOENT) {
-                       ulist_free(ctx->roots);
-                       ctx->roots = NULL;
+                       if (roots_ulist_allocated) {
+                               ulist_free(ctx->roots);
+                               ctx->roots = NULL;
+                       }
                        break;
                }
                ret = 0;
@@ -2295,6 +2301,11 @@ int iterate_extent_inodes(struct btrfs_backref_walk_ctx *ctx,
                    ctx->bytenr);
 
        ASSERT(ctx->trans == NULL);
+       ASSERT(ctx->roots == NULL);
+
+       ctx->roots = ulist_alloc(GFP_NOFS);
+       if (!ctx->roots)
+               return -ENOMEM;
 
        if (!search_commit_root) {
                struct btrfs_trans_handle *trans;
@@ -2302,8 +2313,11 @@ int iterate_extent_inodes(struct btrfs_backref_walk_ctx *ctx,
                trans = btrfs_attach_transaction(ctx->fs_info->tree_root);
                if (IS_ERR(trans)) {
                        if (PTR_ERR(trans) != -ENOENT &&
-                           PTR_ERR(trans) != -EROFS)
+                           PTR_ERR(trans) != -EROFS) {
+                               ulist_free(ctx->roots);
+                               ctx->roots = NULL;
                                return PTR_ERR(trans);
+                       }
                        trans = NULL;
                }
                ctx->trans = trans;
@@ -2344,8 +2358,7 @@ int iterate_extent_inodes(struct btrfs_backref_walk_ctx *ctx,
                                                root_node->val, ctx->bytenr,
                                                iterate, user_ctx);
                }
-               ulist_free(ctx->roots);
-               ctx->roots = NULL;
+               ulist_reinit(ctx->roots);
        }
 
        free_leaf_list(refs);
@@ -2358,6 +2371,9 @@ out:
                up_read(&ctx->fs_info->commit_root_sem);
        }
 
+       ulist_free(ctx->roots);
+       ctx->roots = NULL;
+
        return ret;
 }