struct rb_node *node;
 
        while ((node = rb_first_cached(&tree->root))) {
+               struct btrfs_tree_parent_check check = { 0 };
+
                ref = rb_entry(node, struct prelim_ref, rbnode);
                rb_erase_cached(node, &tree->root);
 
                BUG_ON(ref->key_for_search.type);
                BUG_ON(!ref->wanted_disk_byte);
 
-               eb = read_tree_block(fs_info, ref->wanted_disk_byte,
-                                    ref->root_id, 0, ref->level - 1, NULL);
+               check.level = ref->level - 1;
+               check.owner_root = ref->root_id;
+
+               eb = read_tree_block(fs_info, ref->wanted_disk_byte, &check);
                if (IS_ERR(eb)) {
                        free_pref(ref);
                        return PTR_ERR(eb);
                if (ref->count && ref->parent) {
                        if (!ctx->ignore_extent_item_pos && !ref->inode_list &&
                            ref->level == 0) {
+                               struct btrfs_tree_parent_check check = { 0 };
                                struct extent_buffer *eb;
 
-                               eb = read_tree_block(ctx->fs_info, ref->parent, 0,
-                                                    0, ref->level, NULL);
+                               check.level = ref->level;
+
+                               eb = read_tree_block(ctx->fs_info, ref->parent,
+                                                    &check);
                                if (IS_ERR(eb)) {
                                        ret = PTR_ERR(eb);
                                        goto out;
 
                                           int slot)
 {
        int level = btrfs_header_level(parent);
+       struct btrfs_tree_parent_check check = { 0 };
        struct extent_buffer *eb;
-       struct btrfs_key first_key;
 
        if (slot < 0 || slot >= btrfs_header_nritems(parent))
                return ERR_PTR(-ENOENT);
 
        BUG_ON(level == 0);
 
-       btrfs_node_key_to_cpu(parent, &first_key, slot);
+       check.level = level - 1;
+       check.transid = btrfs_node_ptr_generation(parent, slot);
+       check.owner_root = btrfs_header_owner(parent);
+       check.has_first_key = true;
+       btrfs_node_key_to_cpu(parent, &check.first_key, slot);
+
        eb = read_tree_block(parent->fs_info, btrfs_node_blockptr(parent, slot),
-                            btrfs_header_owner(parent),
-                            btrfs_node_ptr_generation(parent, slot),
-                            level - 1, &first_key);
+                            &check);
        if (IS_ERR(eb))
                return eb;
        if (!extent_buffer_uptodate(eb)) {
                      const struct btrfs_key *key)
 {
        struct btrfs_fs_info *fs_info = root->fs_info;
+       struct btrfs_tree_parent_check check = { 0 };
        u64 blocknr;
        u64 gen;
        struct extent_buffer *tmp;
-       struct btrfs_key first_key;
        int ret;
        int parent_level;
        bool unlock_up;
        blocknr = btrfs_node_blockptr(*eb_ret, slot);
        gen = btrfs_node_ptr_generation(*eb_ret, slot);
        parent_level = btrfs_header_level(*eb_ret);
-       btrfs_node_key_to_cpu(*eb_ret, &first_key, slot);
+       btrfs_node_key_to_cpu(*eb_ret, &check.first_key, slot);
+       check.has_first_key = true;
+       check.level = parent_level - 1;
+       check.transid = gen;
+       check.owner_root = root->root_key.objectid;
 
        /*
         * If we need to read an extent buffer from disk and we are holding locks
                         * parents (shared tree blocks).
                         */
                        if (btrfs_verify_level_key(tmp,
-                                       parent_level - 1, &first_key, gen)) {
+                                       parent_level - 1, &check.first_key, gen)) {
                                free_extent_buffer(tmp);
                                return -EUCLEAN;
                        }
                        btrfs_unlock_up_safe(p, level + 1);
 
                /* now we're allowed to do a blocking uptodate check */
-               ret = btrfs_read_extent_buffer(tmp, gen, parent_level - 1, &first_key);
+               ret = btrfs_read_extent_buffer(tmp, &check);
                if (ret) {
                        free_extent_buffer(tmp);
                        btrfs_release_path(p);
        if (p->reada != READA_NONE)
                reada_for_search(fs_info, p, level, slot, key->objectid);
 
-       tmp = read_tree_block(fs_info, blocknr, root->root_key.objectid,
-                             gen, parent_level - 1, &first_key);
+       tmp = read_tree_block(fs_info, blocknr, &check);
        if (IS_ERR(tmp)) {
                btrfs_release_path(p);
                return PTR_ERR(tmp);
 
  * helper to read a given tree block, doing retries as required when
  * the checksums don't match and we have alternate mirrors to try.
  *
- * @parent_transid:    expected transid, skip check if 0
- * @level:             expected level, mandatory check
- * @first_key:         expected key of first slot, skip check if NULL
+ * @check:             expected tree parentness check, see the comments of the
+ *                     structure for details.
  */
 int btrfs_read_extent_buffer(struct extent_buffer *eb,
-                            u64 parent_transid, int level,
-                            struct btrfs_key *first_key)
+                            struct btrfs_tree_parent_check *check)
 {
        struct btrfs_fs_info *fs_info = eb->fs_info;
        struct extent_io_tree *io_tree;
        int mirror_num = 0;
        int failed_mirror = 0;
 
+       ASSERT(check);
+
        io_tree = &BTRFS_I(fs_info->btree_inode)->io_tree;
        while (1) {
                clear_bit(EXTENT_BUFFER_CORRUPT, &eb->bflags);
                ret = read_extent_buffer_pages(eb, WAIT_COMPLETE, mirror_num);
                if (!ret) {
-                       if (verify_parent_transid(io_tree, eb,
-                                                  parent_transid, 0))
+                       if (verify_parent_transid(io_tree, eb, check->transid, 0))
                                ret = -EIO;
-                       else if (btrfs_verify_level_key(eb, level,
-                                               first_key, parent_transid))
+                       else if (btrfs_verify_level_key(eb, check->level,
+                                               check->has_first_key ?
+                                               &check->first_key : NULL,
+                                               check->transid))
                                ret = -EUCLEAN;
                        else
                                break;
  * Read tree block at logical address @bytenr and do variant basic but critical
  * verification.
  *
- * @owner_root:                the objectid of the root owner for this block.
- * @parent_transid:    expected transid of this tree block, skip check if 0
- * @level:             expected level, mandatory check
- * @first_key:         expected key in slot 0, skip check if NULL
+ * @check:             expected tree parentness check, see comments of the
+ *                     structure for details.
  */
 struct extent_buffer *read_tree_block(struct btrfs_fs_info *fs_info, u64 bytenr,
-                                     u64 owner_root, u64 parent_transid,
-                                     int level, struct btrfs_key *first_key)
+                                     struct btrfs_tree_parent_check *check)
 {
        struct extent_buffer *buf = NULL;
        int ret;
 
-       buf = btrfs_find_create_tree_block(fs_info, bytenr, owner_root, level);
+       ASSERT(check);
+
+       buf = btrfs_find_create_tree_block(fs_info, bytenr, check->owner_root,
+                                          check->level);
        if (IS_ERR(buf))
                return buf;
 
-       ret = btrfs_read_extent_buffer(buf, parent_transid, level, first_key);
+       ret = btrfs_read_extent_buffer(buf, check);
        if (ret) {
                free_extent_buffer_stale(buf);
                return ERR_PTR(ret);
        }
-       if (btrfs_check_eb_owner(buf, owner_root)) {
+       if (btrfs_check_eb_owner(buf, check->owner_root)) {
                free_extent_buffer_stale(buf);
                return ERR_PTR(-EUCLEAN);
        }
                                              struct btrfs_key *key)
 {
        struct btrfs_root *root;
+       struct btrfs_tree_parent_check check = { 0 };
        struct btrfs_fs_info *fs_info = tree_root->fs_info;
        u64 generation;
        int ret;
 
        generation = btrfs_root_generation(&root->root_item);
        level = btrfs_root_level(&root->root_item);
-       root->node = read_tree_block(fs_info,
-                                    btrfs_root_bytenr(&root->root_item),
-                                    key->objectid, generation, level, NULL);
+       check.level = level;
+       check.transid = generation;
+       check.owner_root = key->objectid;
+       root->node = read_tree_block(fs_info, btrfs_root_bytenr(&root->root_item),
+                                    &check);
        if (IS_ERR(root->node)) {
                ret = PTR_ERR(root->node);
                root->node = NULL;
                            struct btrfs_fs_devices *fs_devices)
 {
        int ret;
+       struct btrfs_tree_parent_check check = { 0 };
        struct btrfs_root *log_tree_root;
        struct btrfs_super_block *disk_super = fs_info->super_copy;
        u64 bytenr = btrfs_super_log_root(disk_super);
        if (!log_tree_root)
                return -ENOMEM;
 
-       log_tree_root->node = read_tree_block(fs_info, bytenr,
-                                             BTRFS_TREE_LOG_OBJECTID,
-                                             fs_info->generation + 1, level,
-                                             NULL);
+       check.level = level;
+       check.transid = fs_info->generation + 1;
+       check.owner_root = BTRFS_TREE_LOG_OBJECTID;
+       log_tree_root->node = read_tree_block(fs_info, bytenr, &check);
        if (IS_ERR(log_tree_root->node)) {
                btrfs_warn(fs_info, "failed to read log tree");
                ret = PTR_ERR(log_tree_root->node);
 
 static int load_super_root(struct btrfs_root *root, u64 bytenr, u64 gen, int level)
 {
+       struct btrfs_tree_parent_check check = {
+               .level = level,
+               .transid = gen,
+               .owner_root = root->root_key.objectid
+       };
        int ret = 0;
 
-       root->node = read_tree_block(root->fs_info, bytenr,
-                                    root->root_key.objectid, gen, level, NULL);
+       root->node = read_tree_block(root->fs_info, bytenr, &check);
        if (IS_ERR(root->node)) {
                ret = PTR_ERR(root->node);
                root->node = NULL;
 
        return BTRFS_SUPER_INFO_OFFSET;
 }
 
+/* All the extra info needed to verify the parentness of a tree block. */
+struct btrfs_tree_parent_check {
+       /*
+        * The owner check against the tree block.
+        *
+        * Can be 0 to skip the owner check.
+        */
+       u64 owner_root;
+
+       /*
+        * Expected transid, can be 0 to skip the check, but such skip
+        * should only be utlized for backref walk related code.
+        */
+       u64 transid;
+
+       /*
+        * The expected first key.
+        *
+        * This check can be skipped if @has_first_key is false, such skip
+        * can happen for case where we don't have the parent node key,
+        * e.g. reading the tree root, doing backref walk.
+        */
+       struct btrfs_key first_key;
+       bool has_first_key;
+
+       /* The expected level. Should always be set. */
+       u8 level;
+};
+
 struct btrfs_device;
 struct btrfs_fs_devices;
 
 int btrfs_verify_level_key(struct extent_buffer *eb, int level,
                           struct btrfs_key *first_key, u64 parent_transid);
 struct extent_buffer *read_tree_block(struct btrfs_fs_info *fs_info, u64 bytenr,
-                                     u64 owner_root, u64 parent_transid,
-                                     int level, struct btrfs_key *first_key);
+                                     struct btrfs_tree_parent_check *check);
 struct extent_buffer *btrfs_find_create_tree_block(
                                                struct btrfs_fs_info *fs_info,
                                                u64 bytenr, u64 owner_root,
 void btrfs_mark_buffer_dirty(struct extent_buffer *buf);
 int btrfs_buffer_uptodate(struct extent_buffer *buf, u64 parent_transid,
                          int atomic);
-int btrfs_read_extent_buffer(struct extent_buffer *buf, u64 parent_transid,
-                            int level, struct btrfs_key *first_key);
+int btrfs_read_extent_buffer(struct extent_buffer *buf,
+                            struct btrfs_tree_parent_check *check);
 
 enum btrfs_wq_submit_cmd {
        WQ_SUBMIT_METADATA,
 
        u64 bytenr;
        u64 generation;
        u64 parent;
+       struct btrfs_tree_parent_check check = { 0 };
        struct btrfs_key key;
-       struct btrfs_key first_key;
        struct btrfs_ref ref = { 0 };
        struct extent_buffer *next;
        int level = wc->level;
        }
 
        bytenr = btrfs_node_blockptr(path->nodes[level], path->slots[level]);
-       btrfs_node_key_to_cpu(path->nodes[level], &first_key,
+
+       check.level = level - 1;
+       check.transid = generation;
+       check.owner_root = root->root_key.objectid;
+       check.has_first_key = true;
+       btrfs_node_key_to_cpu(path->nodes[level], &check.first_key,
                              path->slots[level]);
 
        next = find_extent_buffer(fs_info, bytenr);
        if (!next) {
                if (reada && level == 1)
                        reada_walk_down(trans, root, wc, path);
-               next = read_tree_block(fs_info, bytenr, root->root_key.objectid,
-                                      generation, level - 1, &first_key);
+               next = read_tree_block(fs_info, bytenr, &check);
                if (IS_ERR(next)) {
                        return PTR_ERR(next);
                } else if (!extent_buffer_uptodate(next)) {
 
        if (!follow)
                return;
        for (i = 0; i < nr; i++) {
-               struct btrfs_key first_key;
+               struct btrfs_tree_parent_check check = {
+                       .level = level - 1,
+                       .transid = btrfs_node_ptr_generation(c, i),
+                       .owner_root = btrfs_header_owner(c),
+                       .has_first_key = true
+               };
                struct extent_buffer *next;
 
-               btrfs_node_key_to_cpu(c, &first_key, i);
-               next = read_tree_block(fs_info, btrfs_node_blockptr(c, i),
-                                      btrfs_header_owner(c),
-                                      btrfs_node_ptr_generation(c, i),
-                                      level - 1, &first_key);
+               btrfs_node_key_to_cpu(c, &check.first_key, i);
+               next = read_tree_block(fs_info, btrfs_node_blockptr(c, i), &check);
                if (IS_ERR(next))
                        continue;
                if (!extent_buffer_uptodate(next)) {
 
        }
 
        if (!extent_buffer_uptodate(root_eb)) {
-               ret = btrfs_read_extent_buffer(root_eb, root_gen, root_level, NULL);
+               struct btrfs_tree_parent_check check = {
+                       .has_first_key = false,
+                       .transid = root_gen,
+                       .level = root_level
+               };
+
+               ret = btrfs_read_extent_buffer(root_eb, &check);
                if (ret)
                        goto out;
        }
                                         struct extent_buffer *subvol_eb)
 {
        struct btrfs_fs_info *fs_info = root->fs_info;
+       struct btrfs_tree_parent_check check = { 0 };
        struct btrfs_qgroup_swapped_blocks *blocks = &root->swapped_blocks;
        struct btrfs_qgroup_swapped_block *block;
        struct extent_buffer *reloc_eb = NULL;
        blocks->swapped = swapped;
        spin_unlock(&blocks->lock);
 
+       check.level = block->level;
+       check.transid = block->reloc_generation;
+       check.has_first_key = true;
+       memcpy(&check.first_key, &block->first_key, sizeof(check.first_key));
+
        /* Read out reloc subtree root */
-       reloc_eb = read_tree_block(fs_info, block->reloc_bytenr, 0,
-                                  block->reloc_generation, block->level,
-                                  &block->first_key);
+       reloc_eb = read_tree_block(fs_info, block->reloc_bytenr, &check);
        if (IS_ERR(reloc_eb)) {
                ret = PTR_ERR(reloc_eb);
                reloc_eb = NULL;
 
 static int get_tree_block_key(struct btrfs_fs_info *fs_info,
                              struct tree_block *block)
 {
+       struct btrfs_tree_parent_check check = {
+               .level = block->level,
+               .owner_root = block->owner,
+               .transid = block->key.offset
+       };
        struct extent_buffer *eb;
 
-       eb = read_tree_block(fs_info, block->bytenr, block->owner,
-                            block->key.offset, block->level, NULL);
+       eb = read_tree_block(fs_info, block->bytenr, &check);
        if (IS_ERR(eb))
                return PTR_ERR(eb);
        if (!extent_buffer_uptodate(eb)) {
 
        ULIST_ITER_INIT(&leaf_uiter);
        while ((ref_node = ulist_next(ctx.refs, &leaf_uiter))) {
+               struct btrfs_tree_parent_check check = { 0 };
                struct extent_buffer *eb;
 
-               eb = read_tree_block(ctx.fs_info, ref_node->val, 0, 0, 0, NULL);
+               eb = read_tree_block(ctx.fs_info, ref_node->val, &check);
                if (IS_ERR(eb)) {
                        ret = PTR_ERR(eb);
                        break;
 
         * pin down any logged extents, so we have to read the block.
         */
        if (btrfs_fs_incompat(fs_info, MIXED_GROUPS)) {
-               ret = btrfs_read_extent_buffer(eb, gen, level, NULL);
+               struct btrfs_tree_parent_check check = {
+                       .level = level,
+                       .transid = gen
+               };
+
+               ret = btrfs_read_extent_buffer(eb, &check);
                if (ret)
                        return ret;
        }
                             struct walk_control *wc, u64 gen, int level)
 {
        int nritems;
+       struct btrfs_tree_parent_check check = {
+               .transid = gen,
+               .level = level
+       };
        struct btrfs_path *path;
        struct btrfs_root *root = wc->replay_dest;
        struct btrfs_key key;
        int i;
        int ret;
 
-       ret = btrfs_read_extent_buffer(eb, gen, level, NULL);
+       ret = btrfs_read_extent_buffer(eb, &check);
        if (ret)
                return ret;
 
        int ret = 0;
 
        while (*level > 0) {
-               struct btrfs_key first_key;
+               struct btrfs_tree_parent_check check = { 0 };
 
                cur = path->nodes[*level];
 
 
                bytenr = btrfs_node_blockptr(cur, path->slots[*level]);
                ptr_gen = btrfs_node_ptr_generation(cur, path->slots[*level]);
-               btrfs_node_key_to_cpu(cur, &first_key, path->slots[*level]);
+               check.transid = ptr_gen;
+               check.level = *level - 1;
+               check.has_first_key = true;
+               btrfs_node_key_to_cpu(cur, &check.first_key, path->slots[*level]);
                blocksize = fs_info->nodesize;
 
                next = btrfs_find_create_tree_block(fs_info, bytenr,
 
                        path->slots[*level]++;
                        if (wc->free) {
-                               ret = btrfs_read_extent_buffer(next, ptr_gen,
-                                                       *level - 1, &first_key);
+                               ret = btrfs_read_extent_buffer(next, &check);
                                if (ret) {
                                        free_extent_buffer(next);
                                        return ret;
                        free_extent_buffer(next);
                        continue;
                }
-               ret = btrfs_read_extent_buffer(next, ptr_gen, *level - 1, &first_key);
+               ret = btrfs_read_extent_buffer(next, &check);
                if (ret) {
                        free_extent_buffer(next);
                        return ret;
 
 
        tm = tree_mod_log_search(fs_info, logical, time_seq);
        if (old_root && tm && tm->op != BTRFS_MOD_LOG_KEY_REMOVE_WHILE_FREEING) {
+               struct btrfs_tree_parent_check check = { 0 };
+
                btrfs_tree_read_unlock(eb_root);
                free_extent_buffer(eb_root);
-               old = read_tree_block(fs_info, logical, root->root_key.objectid,
-                                     0, level, NULL);
+
+               check.level = level;
+               check.owner_root = root->root_key.objectid;
+
+               old = read_tree_block(fs_info, logical, &check);
                if (WARN_ON(IS_ERR(old) || !extent_buffer_uptodate(old))) {
                        if (!IS_ERR(old))
                                free_extent_buffer(old);