OSDN Git Service

btrfs: reloc: use btrfs_backref_iter infrastructure
authorQu Wenruo <wqu@suse.com>
Fri, 14 Feb 2020 05:48:20 +0000 (13:48 +0800)
committerDavid Sterba <dsterba@suse.com>
Mon, 25 May 2020 09:25:16 +0000 (11:25 +0200)
In the core function of relocation, build_backref_tree, it needs to
iterate all backref items of one tree block.

Use btrfs_backref_iter infrastructure to do the loop and make the code
more readable.

The backref items look would be much more easier to read:

ret = btrfs_backref_iter_start(iter, cur->bytenr);
for (; ret == 0; ret = btrfs_backref_iter_next(iter)) {
/* The really important work */
}

Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Reviewed-by: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: Qu Wenruo <wqu@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/relocation.c

index 03bc713..97a29bf 100644 (file)
@@ -654,48 +654,6 @@ static struct btrfs_root *read_fs_root(struct btrfs_fs_info *fs_info,
        return btrfs_get_fs_root(fs_info, &key, false);
 }
 
-static noinline_for_stack
-int find_inline_backref(struct extent_buffer *leaf, int slot,
-                       unsigned long *ptr, unsigned long *end)
-{
-       struct btrfs_key key;
-       struct btrfs_extent_item *ei;
-       struct btrfs_tree_block_info *bi;
-       u32 item_size;
-
-       btrfs_item_key_to_cpu(leaf, &key, slot);
-
-       item_size = btrfs_item_size_nr(leaf, slot);
-       if (item_size < sizeof(*ei)) {
-               btrfs_print_v0_err(leaf->fs_info);
-               btrfs_handle_fs_error(leaf->fs_info, -EINVAL, NULL);
-               return 1;
-       }
-       ei = btrfs_item_ptr(leaf, slot, struct btrfs_extent_item);
-       WARN_ON(!(btrfs_extent_flags(leaf, ei) &
-                 BTRFS_EXTENT_FLAG_TREE_BLOCK));
-
-       if (key.type == BTRFS_EXTENT_ITEM_KEY &&
-           item_size <= sizeof(*ei) + sizeof(*bi)) {
-               WARN_ON(item_size < sizeof(*ei) + sizeof(*bi));
-               return 1;
-       }
-       if (key.type == BTRFS_METADATA_ITEM_KEY &&
-           item_size <= sizeof(*ei)) {
-               WARN_ON(item_size < sizeof(*ei));
-               return 1;
-       }
-
-       if (key.type == BTRFS_EXTENT_ITEM_KEY) {
-               bi = (struct btrfs_tree_block_info *)(ei + 1);
-               *ptr = (unsigned long)(bi + 1);
-       } else {
-               *ptr = (unsigned long)(ei + 1);
-       }
-       *end = (unsigned long)ei + item_size;
-       return 0;
-}
-
 /*
  * build backref tree for a given tree block. root of the backref tree
  * corresponds the tree block, leaves of the backref tree correspond
@@ -715,10 +673,10 @@ struct backref_node *build_backref_tree(struct reloc_control *rc,
                                        struct btrfs_key *node_key,
                                        int level, u64 bytenr)
 {
+       struct btrfs_backref_iter *iter;
        struct backref_cache *cache = &rc->backref_cache;
-       struct btrfs_path *path1; /* For searching extent root */
-       struct btrfs_path *path2; /* For searching parent of TREE_BLOCK_REF */
-       struct extent_buffer *eb;
+       /* For searching parent of TREE_BLOCK_REF */
+       struct btrfs_path *path;
        struct btrfs_root *root;
        struct backref_node *cur;
        struct backref_node *upper;
@@ -727,9 +685,6 @@ struct backref_node *build_backref_tree(struct reloc_control *rc,
        struct backref_node *exist = NULL;
        struct backref_edge *edge;
        struct rb_node *rb_node;
-       struct btrfs_key key;
-       unsigned long end;
-       unsigned long ptr;
        LIST_HEAD(list); /* Pending edge list, upper node needs to be checked */
        LIST_HEAD(useless);
        int cowonly;
@@ -737,9 +692,11 @@ struct backref_node *build_backref_tree(struct reloc_control *rc,
        int err = 0;
        bool need_check = true;
 
-       path1 = btrfs_alloc_path();
-       path2 = btrfs_alloc_path();
-       if (!path1 || !path2) {
+       iter = btrfs_backref_iter_alloc(rc->extent_root->fs_info, GFP_NOFS);
+       if (!iter)
+               return ERR_PTR(-ENOMEM);
+       path = btrfs_alloc_path();
+       if (!path) {
                err = -ENOMEM;
                goto out;
        }
@@ -755,25 +712,28 @@ struct backref_node *build_backref_tree(struct reloc_control *rc,
        node->lowest = 1;
        cur = node;
 again:
-       end = 0;
-       ptr = 0;
-       key.objectid = cur->bytenr;
-       key.type = BTRFS_METADATA_ITEM_KEY;
-       key.offset = (u64)-1;
-
-       path1->search_commit_root = 1;
-       path1->skip_locking = 1;
-       ret = btrfs_search_slot(NULL, rc->extent_root, &key, path1,
-                               0, 0);
+       ret = btrfs_backref_iter_start(iter, cur->bytenr);
        if (ret < 0) {
                err = ret;
                goto out;
        }
-       ASSERT(ret);
-       ASSERT(path1->slots[0]);
-
-       path1->slots[0]--;
 
+       /*
+        * We skip the first btrfs_tree_block_info, as we don't use the key
+        * stored in it, but fetch it from the tree block
+        */
+       if (btrfs_backref_has_tree_block_info(iter)) {
+               ret = btrfs_backref_iter_next(iter);
+               if (ret < 0) {
+                       err = ret;
+                       goto out;
+               }
+               /* No extra backref? This means the tree block is corrupted */
+               if (ret > 0) {
+                       err = -EUCLEAN;
+                       goto out;
+               }
+       }
        WARN_ON(cur->checked);
        if (!list_empty(&cur->upper)) {
                /*
@@ -795,42 +755,21 @@ again:
                exist = NULL;
        }
 
-       while (1) {
-               cond_resched();
-               eb = path1->nodes[0];
-
-               if (ptr >= end) {
-                       if (path1->slots[0] >= btrfs_header_nritems(eb)) {
-                               ret = btrfs_next_leaf(rc->extent_root, path1);
-                               if (ret < 0) {
-                                       err = ret;
-                                       goto out;
-                               }
-                               if (ret > 0)
-                                       break;
-                               eb = path1->nodes[0];
-                       }
+       for (; ret == 0; ret = btrfs_backref_iter_next(iter)) {
+               struct extent_buffer *eb;
+               struct btrfs_key key;
+               int type;
 
-                       btrfs_item_key_to_cpu(eb, &key, path1->slots[0]);
-                       if (key.objectid != cur->bytenr) {
-                               WARN_ON(exist);
-                               break;
-                       }
+               cond_resched();
+               eb = btrfs_backref_get_eb(iter);
 
-                       if (key.type == BTRFS_EXTENT_ITEM_KEY ||
-                           key.type == BTRFS_METADATA_ITEM_KEY) {
-                               ret = find_inline_backref(eb, path1->slots[0],
-                                                         &ptr, &end);
-                               if (ret)
-                                       goto next;
-                       }
-               }
+               key.objectid = iter->bytenr;
+               if (btrfs_backref_iter_is_inline_ref(iter)) {
+                       struct btrfs_extent_inline_ref *iref;
 
-               if (ptr < end) {
                        /* update key for inline back ref */
-                       struct btrfs_extent_inline_ref *iref;
-                       int type;
-                       iref = (struct btrfs_extent_inline_ref *)ptr;
+                       iref = (struct btrfs_extent_inline_ref *)
+                               ((unsigned long)iter->cur_ptr);
                        type = btrfs_get_extent_inline_ref_type(eb, iref,
                                                        BTRFS_REF_TYPE_BLOCK);
                        if (type == BTRFS_REF_TYPE_INVALID) {
@@ -839,9 +778,9 @@ again:
                        }
                        key.type = type;
                        key.offset = btrfs_extent_inline_ref_offset(eb, iref);
-
-                       WARN_ON(key.type != BTRFS_TREE_BLOCK_REF_KEY &&
-                               key.type != BTRFS_SHARED_BLOCK_REF_KEY);
+               } else {
+                       key.type = iter->cur_key.type;
+                       key.offset = iter->cur_key.offset;
                }
 
                /*
@@ -854,7 +793,7 @@ again:
                     (key.type == BTRFS_SHARED_BLOCK_REF_KEY &&
                      exist->bytenr == key.offset))) {
                        exist = NULL;
-                       goto next;
+                       continue;
                }
 
                /* SHARED_BLOCK_REF means key.offset is the parent bytenr */
@@ -900,7 +839,7 @@ again:
                        edge->node[LOWER] = cur;
                        edge->node[UPPER] = upper;
 
-                       goto next;
+                       continue;
                } else if (unlikely(key.type == BTRFS_EXTENT_REF_V0_KEY)) {
                        err = -EINVAL;
                        btrfs_print_v0_err(rc->extent_root->fs_info);
@@ -908,7 +847,7 @@ again:
                                              NULL);
                        goto out;
                } else if (key.type != BTRFS_TREE_BLOCK_REF_KEY) {
-                       goto next;
+                       continue;
                }
 
                /*
@@ -941,21 +880,21 @@ again:
                level = cur->level + 1;
 
                /* Search the tree to find parent blocks referring the block. */
-               path2->search_commit_root = 1;
-               path2->skip_locking = 1;
-               path2->lowest_level = level;
-               ret = btrfs_search_slot(NULL, root, node_key, path2, 0, 0);
-               path2->lowest_level = 0;
+               path->search_commit_root = 1;
+               path->skip_locking = 1;
+               path->lowest_level = level;
+               ret = btrfs_search_slot(NULL, root, node_key, path, 0, 0);
+               path->lowest_level = 0;
                if (ret < 0) {
                        btrfs_put_root(root);
                        err = ret;
                        goto out;
                }
-               if (ret > 0 && path2->slots[level] > 0)
-                       path2->slots[level]--;
+               if (ret > 0 && path->slots[level] > 0)
+                       path->slots[level]--;
 
-               eb = path2->nodes[level];
-               if (btrfs_node_blockptr(eb, path2->slots[level]) !=
+               eb = path->nodes[level];
+               if (btrfs_node_blockptr(eb, path->slots[level]) !=
                    cur->bytenr) {
                        btrfs_err(root->fs_info,
        "couldn't find block (%llu) (level %d) in tree (%llu) with key (%llu %u %llu)",
@@ -972,7 +911,7 @@ again:
 
                /* Add all nodes and edges in the path */
                for (; level < BTRFS_MAX_LEVEL; level++) {
-                       if (!path2->nodes[level]) {
+                       if (!path->nodes[level]) {
                                ASSERT(btrfs_root_bytenr(&root->root_item) ==
                                       lower->bytenr);
                                if (should_ignore_root(root)) {
@@ -991,7 +930,7 @@ again:
                                goto out;
                        }
 
-                       eb = path2->nodes[level];
+                       eb = path->nodes[level];
                        rb_node = tree_search(&cache->rb_root, eb->start);
                        if (!rb_node) {
                                upper = alloc_backref_node(cache);
@@ -1051,20 +990,14 @@ again:
                        lower = upper;
                        upper = NULL;
                }
-               btrfs_release_path(path2);
-next:
-               if (ptr < end) {
-                       ptr += btrfs_extent_inline_ref_size(key.type);
-                       if (ptr >= end) {
-                               WARN_ON(ptr > end);
-                               ptr = 0;
-                               end = 0;
-                       }
-               }
-               if (ptr >= end)
-                       path1->slots[0]++;
+               btrfs_release_path(path);
+       }
+       if (ret < 0) {
+               err = ret;
+               goto out;
        }
-       btrfs_release_path(path1);
+       ret = 0;
+       btrfs_backref_iter_release(iter);
 
        cur->checked = 1;
        WARN_ON(exist);
@@ -1182,8 +1115,8 @@ next:
                }
        }
 out:
-       btrfs_free_path(path1);
-       btrfs_free_path(path2);
+       btrfs_backref_iter_free(iter);
+       btrfs_free_path(path);
        if (err) {
                while (!list_empty(&useless)) {
                        lower = list_entry(useless.next,