struct btrfs_tree_parent_check *check)
 {
        struct btrfs_fs_info *fs_info = eb->fs_info;
-       struct extent_io_tree *io_tree;
        int failed = 0;
        int ret;
        int num_copies = 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, check->transid, 0))
-                               ret = -EIO;
-                       else if (btrfs_verify_level_key(eb, check->level,
-                                               check->has_first_key ?
-                                               &check->first_key : NULL,
-                                               check->transid))
-                               ret = -EUCLEAN;
-                       else
-                               break;
-               }
+               ret = read_extent_buffer_pages(eb, WAIT_COMPLETE, mirror_num, check);
+               if (!ret)
+                       break;
 
                num_copies = btrfs_num_copies(fs_info,
                                              eb->start, eb->len);
 }
 
 /* Do basic extent buffer checks at read time */
-static int validate_extent_buffer(struct extent_buffer *eb)
+static int validate_extent_buffer(struct extent_buffer *eb,
+                                 struct btrfs_tree_parent_check *check)
 {
        struct btrfs_fs_info *fs_info = eb->fs_info;
        u64 found_start;
        const u8 *header_csum;
        int ret = 0;
 
+       ASSERT(check);
+
        found_start = btrfs_header_bytenr(eb);
        if (found_start != eb->start) {
                btrfs_err_rl(fs_info,
                goto out;
        }
 
+       if (found_level != check->level) {
+               ret = -EIO;
+               goto out;
+       }
+       if (unlikely(check->transid &&
+                    btrfs_header_generation(eb) != check->transid)) {
+               btrfs_err_rl(eb->fs_info,
+"parent transid verify failed on logical %llu mirror %u wanted %llu found %llu",
+                               eb->start, eb->read_mirror, check->transid,
+                               btrfs_header_generation(eb));
+               ret = -EIO;
+               goto out;
+       }
+       if (check->has_first_key) {
+               struct btrfs_key *expect_key = &check->first_key;
+               struct btrfs_key found_key;
+
+               if (found_level)
+                       btrfs_node_key_to_cpu(eb, &found_key, 0);
+               else
+                       btrfs_item_key_to_cpu(eb, &found_key, 0);
+               if (unlikely(btrfs_comp_cpu_keys(expect_key, &found_key))) {
+                       btrfs_err(fs_info,
+"tree first key mismatch detected, bytenr=%llu parent_transid=%llu key expected=(%llu,%u,%llu) has=(%llu,%u,%llu)",
+                                 eb->start, check->transid,
+                                 expect_key->objectid,
+                                 expect_key->type, expect_key->offset,
+                                 found_key.objectid, found_key.type,
+                                 found_key.offset);
+                       ret = -EUCLEAN;
+                       goto out;
+               }
+       }
+       if (check->owner_root) {
+               ret = btrfs_check_eb_owner(eb, check->owner_root);
+               if (ret < 0)
+                       goto out;
+       }
+
        /*
         * If this is a leaf block and it is corrupt, set the corrupt bit so
         * that we don't try and read the other copies of this block, just
 }
 
 static int validate_subpage_buffer(struct page *page, u64 start, u64 end,
-                                  int mirror)
+                                  int mirror, struct btrfs_tree_parent_check *check)
 {
        struct btrfs_fs_info *fs_info = btrfs_sb(page->mapping->host->i_sb);
        struct extent_buffer *eb;
        bool reads_done;
        int ret = 0;
 
+       ASSERT(check);
+
        /*
         * We don't allow bio merge for subpage metadata read, so we should
         * only get one eb for each endio hook.
                ret = -EIO;
                goto err;
        }
-       ret = validate_extent_buffer(eb);
+       ret = validate_extent_buffer(eb, check);
        if (ret < 0)
                goto err;
 
        ASSERT(page->private);
 
        if (btrfs_sb(page->mapping->host->i_sb)->nodesize < PAGE_SIZE)
-               return validate_subpage_buffer(page, start, end, mirror);
+               return validate_subpage_buffer(page, start, end, mirror,
+                                              &bbio->parent_check);
 
        eb = (struct extent_buffer *)page->private;
 
                ret = -EIO;
                goto err;
        }
-       ret = validate_extent_buffer(eb);
+       ret = validate_extent_buffer(eb, &bbio->parent_check);
 err:
        if (ret) {
                /*
        blk_status_t ret;
 
        bio->bi_opf |= REQ_META;
+       bbio->is_metadata = 1;
 
        if (btrfs_op(bio) != BTRFS_MAP_WRITE) {
                btrfs_submit_bio(fs_info, bio, mirror_num);
 
 }
 
 static int read_extent_buffer_subpage(struct extent_buffer *eb, int wait,
-                                     int mirror_num)
+                                     int mirror_num,
+                                     struct btrfs_tree_parent_check *check)
 {
        struct btrfs_fs_info *fs_info = eb->fs_info;
        struct extent_io_tree *io_tree;
 
        ASSERT(!test_bit(EXTENT_BUFFER_UNMAPPED, &eb->bflags));
        ASSERT(PagePrivate(page));
+       ASSERT(check);
        io_tree = &BTRFS_I(fs_info->btree_inode)->io_tree;
 
        if (wait == WAIT_NONE) {
                 */
                atomic_dec(&eb->io_pages);
        }
+       memcpy(&btrfs_bio(bio_ctrl.bio)->parent_check, check, sizeof(*check));
        submit_one_bio(&bio_ctrl);
        if (ret || wait != WAIT_COMPLETE) {
                free_extent_state(cached_state);
        return ret;
 }
 
-int read_extent_buffer_pages(struct extent_buffer *eb, int wait, int mirror_num)
+int read_extent_buffer_pages(struct extent_buffer *eb, int wait, int mirror_num,
+                            struct btrfs_tree_parent_check *check)
 {
        int i;
        struct page *page;
                return -EIO;
 
        if (eb->fs_info->nodesize < PAGE_SIZE)
-               return read_extent_buffer_subpage(eb, wait, mirror_num);
+               return read_extent_buffer_subpage(eb, wait, mirror_num, check);
 
        num_pages = num_extent_pages(eb);
        for (i = 0; i < num_pages; i++) {
                }
        }
 
+       memcpy(&btrfs_bio(bio_ctrl.bio)->parent_check, check, sizeof(*check));
        submit_one_bio(&bio_ctrl);
 
        if (ret || wait != WAIT_COMPLETE)
 void btrfs_readahead_tree_block(struct btrfs_fs_info *fs_info,
                                u64 bytenr, u64 owner_root, u64 gen, int level)
 {
+       struct btrfs_tree_parent_check check = {
+               .has_first_key = 0,
+               .level = level,
+               .transid = gen
+       };
        struct extent_buffer *eb;
        int ret;
 
                return;
        }
 
-       ret = read_extent_buffer_pages(eb, WAIT_NONE, 0);
+       ret = read_extent_buffer_pages(eb, WAIT_NONE, 0, &check);
        if (ret < 0)
                free_extent_buffer_stale(eb);
        else
 
 #include <linux/btrfs.h>
 #include "async-thread.h"
 #include "messages.h"
+#include "disk-io.h"
 
 #define BTRFS_MAX_DATA_CHUNK_SIZE      (10ULL * SZ_1G)
 
  * Mostly for btrfs specific features like csum and mirror_num.
  */
 struct btrfs_bio {
-       unsigned int mirror_num;
+       unsigned int mirror_num:7;
+
+       /*
+        * Extra indicator for metadata bios.
+        * For some btrfs bios they use pages without a mapping, thus
+        * we can not rely on page->mapping->host to determine if
+        * it's a metadata bio.
+        */
+       unsigned int is_metadata:1;
        struct bvec_iter iter;
 
        /* for direct I/O */
 
        /* @device is for stripe IO submission. */
        struct btrfs_device *device;
-       u8 *csum;
-       u8 csum_inline[BTRFS_BIO_INLINE_CSUM_SIZE];
+       union {
+               /* For data checksum verification. */
+               struct {
+                       u8 *csum;
+                       u8 csum_inline[BTRFS_BIO_INLINE_CSUM_SIZE];
+               };
+
+               /* For metadata parentness verification. */
+               struct btrfs_tree_parent_check parent_check;
+       };
 
        /* End I/O information supplied to btrfs_bio_alloc */
        btrfs_bio_end_io_t end_io;
 
 static inline void btrfs_bio_free_csum(struct btrfs_bio *bbio)
 {
+       if (bbio->is_metadata)
+               return;
        if (bbio->csum != bbio->csum_inline) {
                kfree(bbio->csum);
                bbio->csum = NULL;