btrfs-progs: mkfs: delete un-used parameter fd
[platform/upstream/btrfs-progs.git] / cmds-check.c
index 3d0b123..c5faa2b 100644 (file)
@@ -829,7 +829,8 @@ static void print_inode_error(struct btrfs_root *root, struct inode_record *rec)
                }
                if (!found)
                        fprintf(stderr, "\tstart: 0, len: %llu\n",
-                               round_up(rec->isize, root->sectorsize));
+                               round_up(rec->isize,
+                                        root->fs_info->sectorsize));
        }
 }
 
@@ -1512,13 +1513,19 @@ static int process_dir_item(struct extent_buffer *eb,
                filetype = btrfs_dir_type(eb, di);
 
                rec->found_size += name_len;
-               if (name_len <= BTRFS_NAME_LEN) {
+               if (cur + sizeof(*di) + name_len > total ||
+                   name_len > BTRFS_NAME_LEN) {
+                       error = REF_ERR_NAME_TOO_LONG;
+
+                       if (cur + sizeof(*di) > total)
+                               break;
+                       len = min_t(u32, total - cur - sizeof(*di),
+                                   BTRFS_NAME_LEN);
+               } else {
                        len = name_len;
                        error = 0;
-               } else {
-                       len = BTRFS_NAME_LEN;
-                       error = REF_ERR_NAME_TOO_LONG;
                }
+
                read_extent_buffer(eb, namebuf, (unsigned long)(di + 1), len);
 
                if (location.type == BTRFS_INODE_ITEM_KEY) {
@@ -1569,13 +1576,22 @@ static int process_inode_ref(struct extent_buffer *eb,
        while (cur < total) {
                name_len = btrfs_inode_ref_name_len(eb, ref);
                index = btrfs_inode_ref_index(eb, ref);
-               if (name_len <= BTRFS_NAME_LEN) {
+
+               /* inode_ref + namelen should not cross item boundary */
+               if (cur + sizeof(*ref) + name_len > total ||
+                   name_len > BTRFS_NAME_LEN) {
+                       if (total < cur + sizeof(*ref))
+                               break;
+
+                       /* Still try to read out the remaining part */
+                       len = min_t(u32, total - cur - sizeof(*ref),
+                                   BTRFS_NAME_LEN);
+                       error = REF_ERR_NAME_TOO_LONG;
+               } else {
                        len = name_len;
                        error = 0;
-               } else {
-                       len = BTRFS_NAME_LEN;
-                       error = REF_ERR_NAME_TOO_LONG;
                }
+
                read_extent_buffer(eb, namebuf, (unsigned long)(ref + 1), len);
                add_inode_backref(inode_cache, key->objectid, key->offset,
                                  index, namebuf, len, 0, key->type, error);
@@ -1684,7 +1700,8 @@ static int count_csum_range(struct btrfs_root *root, u64 start,
                        start = key.offset;
 
                size = btrfs_item_size_nr(leaf, path.slots[0]);
-               csum_end = key.offset + (size / csum_size) * root->sectorsize;
+               csum_end = key.offset + (size / csum_size) *
+                          root->fs_info->sectorsize;
                if (csum_end > start) {
                        size = min(csum_end - start, len);
                        len -= size;
@@ -1711,7 +1728,7 @@ static int process_file_extent(struct btrfs_root *root,
        u64 num_bytes = 0;
        u64 disk_bytenr = 0;
        u64 extent_offset = 0;
-       u64 mask = root->sectorsize - 1;
+       u64 mask = root->fs_info->sectorsize - 1;
        int extent_type;
        int ret;
 
@@ -1868,6 +1885,11 @@ static int update_nodes_refs(struct btrfs_root *root, u64 bytenr,
 static int check_inode_item(struct btrfs_root *root, struct btrfs_path *path,
                            unsigned int ext_ref);
 
+/*
+ * Returns >0  Found error, not fatal, should continue
+ * Returns <0  Fatal error, must exit the whole check
+ * Returns 0   No errors found
+ */
 static int process_one_leaf_v2(struct btrfs_root *root, struct btrfs_path *path,
                               struct node_refs *nrefs, int *level, int ext_ref)
 {
@@ -1937,19 +1959,15 @@ again:
        }
 out:
        err &= ~LAST_ITEM;
-       /*
-        * Convert any error bitmap to -EIO, as we should avoid
-        * mixing positive and negative return value to represent
-        * error
-        */
        if (err && !ret)
-               ret = -EIO;
+               ret = err;
        return ret;
 }
 
 static void reada_walk_down(struct btrfs_root *root,
                            struct extent_buffer *node, int slot)
 {
+       struct btrfs_fs_info *fs_info = root->fs_info;
        u64 bytenr;
        u64 ptr_gen;
        u32 nritems;
@@ -1962,11 +1980,11 @@ static void reada_walk_down(struct btrfs_root *root,
                return;
 
        nritems = btrfs_header_nritems(node);
-       blocksize = root->nodesize;
+       blocksize = fs_info->nodesize;
        for (i = slot; i < nritems; i++) {
                bytenr = btrfs_node_blockptr(node, i);
                ptr_gen = btrfs_node_ptr_generation(node, i);
-               readahead_tree_block(root, bytenr, blocksize, ptr_gen);
+               readahead_tree_block(fs_info, bytenr, blocksize, ptr_gen);
        }
 }
 
@@ -2087,6 +2105,7 @@ static int walk_down_tree(struct btrfs_root *root, struct btrfs_path *path,
        enum btrfs_tree_block_status status;
        u64 bytenr;
        u64 ptr_gen;
+       struct btrfs_fs_info *fs_info = root->fs_info;
        struct extent_buffer *next;
        struct extent_buffer *cur;
        u32 blocksize;
@@ -2138,7 +2157,7 @@ static int walk_down_tree(struct btrfs_root *root, struct btrfs_path *path,
                }
                bytenr = btrfs_node_blockptr(cur, path->slots[*level]);
                ptr_gen = btrfs_node_ptr_generation(cur, path->slots[*level]);
-               blocksize = root->nodesize;
+               blocksize = fs_info->nodesize;
 
                if (bytenr == nrefs->bytenr[*level - 1]) {
                        refs = nrefs->refs[*level - 1];
@@ -2162,11 +2181,11 @@ static int walk_down_tree(struct btrfs_root *root, struct btrfs_path *path,
                        }
                }
 
-               next = btrfs_find_tree_block(root, bytenr, blocksize);
+               next = btrfs_find_tree_block(fs_info, bytenr, blocksize);
                if (!next || !btrfs_buffer_uptodate(next, ptr_gen)) {
                        free_extent_buffer(next);
                        reada_walk_down(root, cur, path->slots[*level]);
-                       next = read_tree_block(root, bytenr, blocksize,
+                       next = read_tree_block(root->fs_info, bytenr, blocksize,
                                               ptr_gen);
                        if (!extent_buffer_uptodate(next)) {
                                struct btrfs_key node_key;
@@ -2177,7 +2196,8 @@ static int walk_down_tree(struct btrfs_root *root, struct btrfs_path *path,
                                btrfs_add_corrupt_extent_record(root->fs_info,
                                                &node_key,
                                                path->nodes[*level]->start,
-                                               root->nodesize, *level);
+                                               root->fs_info->nodesize,
+                                               *level);
                                err = -EIO;
                                goto out;
                        }
@@ -2185,6 +2205,7 @@ static int walk_down_tree(struct btrfs_root *root, struct btrfs_path *path,
 
                ret = check_child_node(cur, path->slots[*level], next);
                if (ret) {
+                       free_extent_buffer(next);
                        err = ret;
                        goto out;
                }
@@ -2212,12 +2233,18 @@ out:
 static int check_inode_item(struct btrfs_root *root, struct btrfs_path *path,
                            unsigned int ext_ref);
 
+/*
+ * Returns >0  Found error, should continue
+ * Returns <0  Fatal error, must exit the whole check
+ * Returns 0   No errors found
+ */
 static int walk_down_tree_v2(struct btrfs_root *root, struct btrfs_path *path,
                             int *level, struct node_refs *nrefs, int ext_ref)
 {
        enum btrfs_tree_block_status status;
        u64 bytenr;
        u64 ptr_gen;
+       struct btrfs_fs_info *fs_info = root->fs_info;
        struct extent_buffer *next;
        struct extent_buffer *cur;
        u32 blocksize;
@@ -2260,7 +2287,7 @@ static int walk_down_tree_v2(struct btrfs_root *root, struct btrfs_path *path,
                }
                bytenr = btrfs_node_blockptr(cur, path->slots[*level]);
                ptr_gen = btrfs_node_ptr_generation(cur, path->slots[*level]);
-               blocksize = root->nodesize;
+               blocksize = fs_info->nodesize;
 
                ret = update_nodes_refs(root, bytenr, nrefs, *level - 1);
                if (ret)
@@ -2270,11 +2297,11 @@ static int walk_down_tree_v2(struct btrfs_root *root, struct btrfs_path *path,
                        continue;
                }
 
-               next = btrfs_find_tree_block(root, bytenr, blocksize);
+               next = btrfs_find_tree_block(fs_info, bytenr, blocksize);
                if (!next || !btrfs_buffer_uptodate(next, ptr_gen)) {
                        free_extent_buffer(next);
                        reada_walk_down(root, cur, path->slots[*level]);
-                       next = read_tree_block(root, bytenr, blocksize,
+                       next = read_tree_block(fs_info, bytenr, blocksize,
                                               ptr_gen);
                        if (!extent_buffer_uptodate(next)) {
                                struct btrfs_key node_key;
@@ -2282,10 +2309,11 @@ static int walk_down_tree_v2(struct btrfs_root *root, struct btrfs_path *path,
                                btrfs_node_key_to_cpu(path->nodes[*level],
                                                      &node_key,
                                                      path->slots[*level]);
-                               btrfs_add_corrupt_extent_record(root->fs_info,
+                               btrfs_add_corrupt_extent_record(fs_info,
                                                &node_key,
                                                path->nodes[*level]->start,
-                                               root->nodesize, *level);
+                                               fs_info->nodesize,
+                                               *level);
                                ret = -EIO;
                                break;
                        }
@@ -2661,6 +2689,7 @@ static int repair_inode_backrefs(struct btrfs_root *root,
                        repaired++;
                        list_del(&backref->list);
                        free(backref);
+                       continue;
                }
 
                if (!delete && !backref->found_dir_index &&
@@ -2671,12 +2700,12 @@ static int repair_inode_backrefs(struct btrfs_root *root,
                                break;
                        repaired++;
                        if (backref->found_dir_item &&
-                           backref->found_dir_index &&
                            backref->found_dir_index) {
                                if (!backref->errors &&
                                    backref->found_inode_ref) {
                                        list_del(&backref->list);
                                        free(backref);
+                                       continue;
                                }
                        }
                }
@@ -3210,7 +3239,8 @@ static int repair_inode_discount_extent(struct btrfs_trans_handle *trans,
        /* special case for a file losing all its file extent */
        if (!found) {
                ret = btrfs_punch_hole(trans, root, rec->ino, 0,
-                                      round_up(rec->isize, root->sectorsize));
+                                      round_up(rec->isize,
+                                               root->fs_info->sectorsize));
                if (ret < 0)
                        goto out;
        }
@@ -3830,9 +3860,9 @@ static int repair_btree(struct btrfs_root *root,
                 * return value is not concerned.
                 */
                btrfs_release_path(&path);
-               ret = btrfs_free_extent(trans, root, offset, root->nodesize,
-                                       0, root->root_key.objectid,
-                                       level - 1, 0);
+               ret = btrfs_free_extent(trans, root, offset,
+                               root->fs_info->nodesize, 0,
+                               root->root_key.objectid, level - 1, 0);
                cache = next_cache_extent(cache);
        }
 
@@ -4219,16 +4249,22 @@ static int find_dir_item(struct btrfs_root *root, struct btrfs_key *ref_key,
                if (imode_to_type(mode) != filetype)
                        goto next;
 
-               if (name_len <= BTRFS_NAME_LEN) {
-                       len = name_len;
-               } else {
-                       len = BTRFS_NAME_LEN;
+               if (cur + sizeof(*di) + name_len > total ||
+                   name_len > BTRFS_NAME_LEN) {
                        warning("root %llu %s[%llu %llu] name too long %u, trimmed",
-                       root->objectid,
-                       key->type == BTRFS_DIR_ITEM_KEY ?
-                       "DIR_ITEM" : "DIR_INDEX",
-                       key->objectid, key->offset, name_len);
+                               root->objectid,
+                               key->type == BTRFS_DIR_ITEM_KEY ?
+                               "DIR_ITEM" : "DIR_INDEX",
+                               key->objectid, key->offset, name_len);
+
+                       if (cur + sizeof(*di) > total)
+                               break;
+                       len = min_t(u32, total - cur - sizeof(*di),
+                                   BTRFS_NAME_LEN);
+               } else {
+                       len = name_len;
                }
+
                read_extent_buffer(node, namebuf, (unsigned long)(di + 1), len);
                if (len != namelen || strncmp(namebuf, name, len))
                        goto next;
@@ -4289,12 +4325,16 @@ next:
 
        index = btrfs_inode_ref_index(node, ref);
        name_len = btrfs_inode_ref_name_len(node, ref);
-       if (name_len <= BTRFS_NAME_LEN) {
-               len = name_len;
-       } else {
-               len = BTRFS_NAME_LEN;
+       if (cur + sizeof(*ref) + name_len > total ||
+           name_len > BTRFS_NAME_LEN) {
                warning("root %llu INODE_REF[%llu %llu] name too long",
                        root->objectid, ref_key->objectid, ref_key->offset);
+
+               if (total < cur + sizeof(*ref))
+                       goto out;
+               len = min_t(u32, total - cur - sizeof(*ref), BTRFS_NAME_LEN);
+       } else {
+               len = name_len;
        }
 
        read_extent_buffer(node, namebuf, (unsigned long)(ref + 1), len);
@@ -4327,6 +4367,7 @@ next:
        if (cur < total)
                goto next;
 
+out:
        return err;
 }
 
@@ -4464,16 +4505,22 @@ static int find_inode_ref(struct btrfs_root *root, struct btrfs_key *key,
                if (index != (u64)-1 && index != ref_index)
                        goto next_ref;
 
-               if (ref_namelen <= BTRFS_NAME_LEN) {
-                       len = ref_namelen;
-               } else {
-                       len = BTRFS_NAME_LEN;
+               if (cur + sizeof(*ref) + ref_namelen > total ||
+                   ref_namelen > BTRFS_NAME_LEN) {
                        warning("root %llu INODE %s[%llu %llu] name too long",
                                root->objectid,
                                key->type == BTRFS_INODE_REF_KEY ?
                                        "REF" : "EXTREF",
                                key->objectid, key->offset);
+
+                       if (cur + sizeof(*ref) > total)
+                               break;
+                       len = min_t(u32, total - cur - sizeof(*ref),
+                                   BTRFS_NAME_LEN);
+               } else {
+                       len = ref_namelen;
                }
+
                read_extent_buffer(node, ref_namebuf, (unsigned long)(ref + 1),
                                   len);
 
@@ -4605,15 +4652,20 @@ static int check_dir_item(struct btrfs_root *root, struct btrfs_key *key,
                              key->objectid, key->offset, data_len);
 
                name_len = btrfs_dir_name_len(node, di);
-               if (name_len <= BTRFS_NAME_LEN) {
-                       len = name_len;
-               } else {
-                       len = BTRFS_NAME_LEN;
+               if (cur + sizeof(*di) + name_len > total ||
+                   name_len > BTRFS_NAME_LEN) {
                        warning("root %llu %s[%llu %llu] name too long",
                                root->objectid,
                                key->type == BTRFS_DIR_ITEM_KEY ?
                                "DIR_ITEM" : "DIR_INDEX",
                                key->objectid, key->offset);
+
+                       if (cur + sizeof(*di) > total)
+                               break;
+                       len = min_t(u32, total - cur - sizeof(*di),
+                                   BTRFS_NAME_LEN);
+               } else {
+                       len = name_len;
                }
                (*size) += name_len;
 
@@ -4733,6 +4785,7 @@ static int check_file_extent(struct btrfs_root *root, struct btrfs_key *fkey,
                                extent_num_bytes, item_inline_len);
                        err |= FILE_EXTENT_ERROR;
                }
+               *end += extent_num_bytes;
                *size += extent_num_bytes;
                return err;
        }
@@ -4792,11 +4845,7 @@ static int check_file_extent(struct btrfs_root *root, struct btrfs_key *fkey,
        }
 
        /* Check EXTENT_DATA hole */
-       if (no_holes && is_hole) {
-               err |= FILE_EXTENT_ERROR;
-               error("root %llu EXTENT_DATA[%llu %llu] shouldn't be hole",
-                     root->objectid, fkey->objectid, fkey->offset);
-       } else if (!no_holes && *end != fkey->offset) {
+       if (!no_holes && *end != fkey->offset) {
                err |= FILE_EXTENT_ERROR;
                error("root %llu EXTENT_DATA[%llu %llu] interrupt",
                      root->objectid, fkey->objectid, fkey->offset);
@@ -4937,9 +4986,10 @@ out:
                 * Just a warning, as dir inode nbytes is just an
                 * instructive value.
                 */
-               if (!IS_ALIGNED(nbytes, root->nodesize)) {
+               if (!IS_ALIGNED(nbytes, root->fs_info->nodesize)) {
                        warning("root %llu DIR INODE[%llu] nbytes should be aligned to %u",
-                               root->objectid, inode_id, root->nodesize);
+                               root->objectid, inode_id,
+                               root->fs_info->nodesize);
                }
 
                if (isize != size) {
@@ -4997,6 +5047,8 @@ static int check_fs_first_inode(struct btrfs_root *root, unsigned int ext_ref)
        if (ret > 0) {
                ret = 0;
                err |= INODE_ITEM_MISSING;
+               error("first inode item of root %llu is missing",
+                     root->objectid);
        }
 
        err |= check_inode_item(root, &path, ext_ref);
@@ -5022,8 +5074,9 @@ static int check_fs_root_v2(struct btrfs_root *root, unsigned int ext_ref)
        struct btrfs_path path;
        struct node_refs nrefs;
        struct btrfs_root_item *root_item = &root->root_item;
-       int ret, wret;
+       int ret;
        int level;
+       int err = 0;
 
        /*
         * We need to manually check the first inode item(256)
@@ -5057,17 +5110,21 @@ static int check_fs_root_v2(struct btrfs_root *root, unsigned int ext_ref)
        }
 
        while (1) {
-               wret = walk_down_tree_v2(root, &path, &level, &nrefs, ext_ref);
-               if (wret < 0)
-                       ret = wret;
-               if (wret != 0)
+               ret = walk_down_tree_v2(root, &path, &level, &nrefs, ext_ref);
+               err |= !!ret;
+
+               /* if ret is negative, walk shall stop */
+               if (ret < 0) {
+                       ret = err;
                        break;
+               }
 
-               wret = walk_up_tree_v2(root, &path, &level);
-               if (wret < 0)
-                       ret = wret;
-               if (wret != 0)
+               ret = walk_up_tree_v2(root, &path, &level);
+               if (ret != 0) {
+                       /* Normal exit, reset ret to err */
+                       ret = err;
                        break;
+               }
        }
 
 out:
@@ -6017,6 +6074,7 @@ static int add_extent_rec_nolookup(struct cache_tree *extent_cache,
        struct extent_record *rec;
        int ret = 0;
 
+       BUG_ON(tmpl->max_size == 0);
        rec = malloc(sizeof(*rec));
        if (!rec)
                return -ENOMEM;
@@ -6051,7 +6109,7 @@ static int add_extent_rec_nolookup(struct cache_tree *extent_cache,
 
        if (tmpl->metadata)
                rec->crossing_stripes = check_crossing_stripes(global_info,
-                               rec->start, global_info->tree_root->nodesize);
+                               rec->start, global_info->nodesize);
        check_extent_type(rec);
        return ret;
 }
@@ -6153,7 +6211,7 @@ static int add_extent_rec(struct cache_tree *extent_cache,
                if (tmpl->metadata)
                        rec->crossing_stripes = check_crossing_stripes(
                                        global_info, rec->start,
-                                       global_info->tree_root->nodesize);
+                                       global_info->nodesize);
                check_extent_type(rec);
                maybe_free_extent_rec(extent_cache, rec);
                return ret;
@@ -6180,6 +6238,7 @@ static int add_tree_backref(struct cache_tree *extent_cache, u64 bytenr,
                tmpl.start = bytenr;
                tmpl.nr = 1;
                tmpl.metadata = 1;
+               tmpl.max_size = 1;
 
                ret = add_extent_rec_nolookup(extent_cache, &tmpl);
                if (ret)
@@ -6567,7 +6626,7 @@ static int process_chunk_item(struct cache_tree *chunk_cache,
         * wrong onwer(3) out of chunk tree, to pass both chunk tree check
         * and owner<->key_type check.
         */
-       ret = btrfs_check_chunk_valid(global_info->tree_root, eb, chunk, slot,
+       ret = btrfs_check_chunk_valid(global_info, eb, chunk, slot,
                                      key->offset);
        if (ret < 0) {
                error("chunk(%llu, %llu) is not valid, ignore it",
@@ -6749,14 +6808,14 @@ static int process_extent_item(struct btrfs_root *root,
 
        if (key.type == BTRFS_METADATA_ITEM_KEY) {
                metadata = 1;
-               num_bytes = root->nodesize;
+               num_bytes = root->fs_info->nodesize;
        } else {
                num_bytes = key.offset;
        }
 
-       if (!IS_ALIGNED(key.objectid, root->sectorsize)) {
+       if (!IS_ALIGNED(key.objectid, root->fs_info->sectorsize)) {
                error("ignoring invalid extent, bytenr %llu is not aligned to %u",
-                     key.objectid, root->sectorsize);
+                     key.objectid, root->fs_info->sectorsize);
                return -EIO;
        }
        if (item_size < sizeof(*ei)) {
@@ -6785,14 +6844,14 @@ static int process_extent_item(struct btrfs_root *root,
                metadata = 1;
        else
                metadata = 0;
-       if (metadata && num_bytes != root->nodesize) {
+       if (metadata && num_bytes != root->fs_info->nodesize) {
                error("ignore invalid metadata extent, length %llu does not equal to %u",
-                     num_bytes, root->nodesize);
+                     num_bytes, root->fs_info->nodesize);
                return -EIO;
        }
-       if (!metadata && !IS_ALIGNED(num_bytes, root->sectorsize)) {
+       if (!metadata && !IS_ALIGNED(num_bytes, root->fs_info->sectorsize)) {
                error("ignore invalid data extent, length %llu is not aligned to %u",
-                     num_bytes, root->sectorsize);
+                     num_bytes, root->fs_info->sectorsize);
                return -EIO;
        }
 
@@ -6820,14 +6879,16 @@ static int process_extent_item(struct btrfs_root *root,
                        ret = add_tree_backref(extent_cache, key.objectid,
                                        0, offset, 0);
                        if (ret < 0)
-                               error("add_tree_backref failed: %s",
+                               error(
+                       "add_tree_backref failed (extent items tree block): %s",
                                      strerror(-ret));
                        break;
                case BTRFS_SHARED_BLOCK_REF_KEY:
                        ret = add_tree_backref(extent_cache, key.objectid,
                                        offset, 0, 0);
                        if (ret < 0)
-                               error("add_tree_backref failed: %s",
+                               error(
+                       "add_tree_backref failed (extent items shared block): %s",
                                      strerror(-ret));
                        break;
                case BTRFS_EXTENT_DATA_REF_KEY:
@@ -6871,7 +6932,7 @@ static int check_cache_range(struct btrfs_root *root,
 
        for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) {
                bytenr = btrfs_sb_offset(i);
-               ret = btrfs_rmap_block(&root->fs_info->mapping_tree,
+               ret = btrfs_rmap_block(root->fs_info,
                                       cache->key.objectid, bytenr, 0,
                                       &logical, &nr, &stripe_len);
                if (ret)
@@ -6998,7 +7059,7 @@ static int verify_space_cache(struct btrfs_root *root,
                        if (key.type == BTRFS_EXTENT_ITEM_KEY)
                                last = key.objectid + key.offset;
                        else
-                               last = key.objectid + root->nodesize;
+                               last = key.objectid + root->fs_info->nodesize;
                        path.slots[0]++;
                        continue;
                }
@@ -7010,7 +7071,7 @@ static int verify_space_cache(struct btrfs_root *root,
                if (key.type == BTRFS_EXTENT_ITEM_KEY)
                        last = key.objectid + key.offset;
                else
-                       last = key.objectid + root->nodesize;
+                       last = key.objectid + root->fs_info->nodesize;
                path.slots[0]++;
        }
 
@@ -7060,7 +7121,7 @@ static int check_space_cache(struct btrfs_root *root)
                start = cache->key.objectid + cache->key.offset;
                if (!cache->free_space_ctl) {
                        if (btrfs_init_free_space_ctl(cache,
-                                                     root->sectorsize)) {
+                                               root->fs_info->sectorsize)) {
                                ret = -ENOMEM;
                                break;
                        }
@@ -7108,8 +7169,9 @@ static int check_extent_csums(struct btrfs_root *root, u64 bytenr,
                        u64 num_bytes, unsigned long leaf_offset,
                        struct extent_buffer *eb) {
 
+       struct btrfs_fs_info *fs_info = root->fs_info;
        u64 offset = 0;
-       u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy);
+       u16 csum_size = btrfs_super_csum_size(fs_info->super_copy);
        char *data;
        unsigned long csum_offset;
        u32 csum;
@@ -7121,7 +7183,7 @@ static int check_extent_csums(struct btrfs_root *root, u64 bytenr,
        int mirror;
        int num_copies;
 
-       if (num_bytes % root->sectorsize)
+       if (num_bytes % fs_info->sectorsize)
                return -EINVAL;
 
        data = malloc(num_bytes);
@@ -7133,7 +7195,7 @@ static int check_extent_csums(struct btrfs_root *root, u64 bytenr,
 again:
                read_len = num_bytes - offset;
                /* read as much space once a time */
-               ret = read_extent_data(root, data + offset,
+               ret = read_extent_data(fs_info, data + offset,
                                bytenr + offset, &read_len, mirror);
                if (ret)
                        goto out;
@@ -7144,11 +7206,11 @@ again:
                        tmp = offset + data_checked;
 
                        csum = btrfs_csum_data((char *)data + tmp,
-                                              csum, root->sectorsize);
+                                              csum, fs_info->sectorsize);
                        btrfs_csum_final(csum, (u8 *)&csum);
 
                        csum_offset = leaf_offset +
-                                tmp / root->sectorsize * csum_size;
+                                tmp / fs_info->sectorsize * csum_size;
                        read_extent_buffer(eb, (char *)&csum_expected,
                                           csum_offset, csum_size);
                        /* try another mirror */
@@ -7156,15 +7218,14 @@ again:
                                fprintf(stderr, "mirror %d bytenr %llu csum %u expected csum %u\n",
                                                mirror, bytenr + tmp,
                                                csum, csum_expected);
-                               num_copies = btrfs_num_copies(
-                                               &root->fs_info->mapping_tree,
+                               num_copies = btrfs_num_copies(root->fs_info,
                                                bytenr, num_bytes);
                                if (mirror < num_copies - 1) {
                                        mirror += 1;
                                        goto again;
                                }
                        }
-                       data_checked += root->sectorsize;
+                       data_checked += fs_info->sectorsize;
                }
                offset += read_len;
        }
@@ -7365,7 +7426,7 @@ static int check_csums(struct btrfs_root *root)
                }
 
                data_len = (btrfs_item_size_nr(leaf, path.slots[0]) /
-                             csum_size) * root->sectorsize;
+                             csum_size) * root->fs_info->sectorsize;
                if (!check_data_csum)
                        goto skip_csum_check;
                leaf_offset = btrfs_item_ptr_offset(leaf, path.slots[0]);
@@ -7550,6 +7611,7 @@ static int run_next_block(struct btrfs_root *root,
                          struct device_extent_tree *dev_extent_cache,
                          struct root_item_record *ri)
 {
+       struct btrfs_fs_info *fs_info = root->fs_info;
        struct extent_buffer *buf;
        struct extent_record *rec = NULL;
        u64 bytenr;
@@ -7579,7 +7641,7 @@ static int run_next_block(struct btrfs_root *root,
                                continue;
 
                        /* fixme, get the parent transid */
-                       readahead_tree_block(root, bits[i].start,
+                       readahead_tree_block(fs_info, bits[i].start,
                                             bits[i].size, 0);
                }
        }
@@ -7609,7 +7671,7 @@ static int run_next_block(struct btrfs_root *root,
        }
 
        /* fixme, get the real parent transid */
-       buf = read_tree_block(root, bytenr, size, gen);
+       buf = read_tree_block(root->fs_info, bytenr, size, gen);
        if (!extent_buffer_uptodate(buf)) {
                record_bad_block_io(root->fs_info,
                                    extent_cache, bytenr, size);
@@ -7741,7 +7803,8 @@ static int run_next_block(struct btrfs_root *root,
                                ret = add_tree_backref(extent_cache,
                                                key.objectid, 0, key.offset, 0);
                                if (ret < 0)
-                                       error("add_tree_backref failed: %s",
+                                       error(
+                               "add_tree_backref failed (leaf tree block): %s",
                                              strerror(-ret));
                                continue;
                        }
@@ -7749,7 +7812,8 @@ static int run_next_block(struct btrfs_root *root,
                                ret = add_tree_backref(extent_cache,
                                                key.objectid, key.offset, 0, 0);
                                if (ret < 0)
-                                       error("add_tree_backref failed: %s",
+                                       error(
+                               "add_tree_backref failed (leaf shared block): %s",
                                              strerror(-ret));
                                continue;
                        }
@@ -7764,7 +7828,7 @@ static int run_next_block(struct btrfs_root *root,
                                                                       ref),
                                        btrfs_extent_data_ref_offset(buf, ref),
                                        btrfs_extent_data_ref_count(buf, ref),
-                                       0, root->sectorsize);
+                                       0, root->fs_info->sectorsize);
                                continue;
                        }
                        if (key.type == BTRFS_SHARED_DATA_REF_KEY) {
@@ -7774,7 +7838,7 @@ static int run_next_block(struct btrfs_root *root,
                                add_data_backref(extent_cache,
                                        key.objectid, key.offset, 0, 0, 0,
                                        btrfs_shared_data_ref_count(buf, ref),
-                                       0, root->sectorsize);
+                                       0, root->fs_info->sectorsize);
                                continue;
                        }
                        if (key.type == BTRFS_ORPHAN_ITEM_KEY) {
@@ -7806,7 +7870,7 @@ static int run_next_block(struct btrfs_root *root,
 
                        data_bytes_allocated +=
                                btrfs_file_extent_disk_num_bytes(buf, fi);
-                       if (data_bytes_allocated < root->sectorsize) {
+                       if (data_bytes_allocated < root->fs_info->sectorsize) {
                                abort();
                        }
                        data_bytes_referenced +=
@@ -7830,7 +7894,7 @@ static int run_next_block(struct btrfs_root *root,
                        struct extent_record tmpl;
 
                        ptr = btrfs_node_blockptr(buf, i);
-                       size = root->nodesize;
+                       size = root->fs_info->nodesize;
                        btrfs_node_key_to_cpu(buf, &key, i);
                        if (ri != NULL) {
                                if ((level == ri->drop_level)
@@ -7854,7 +7918,8 @@ static int run_next_block(struct btrfs_root *root,
                        ret = add_tree_backref(extent_cache, ptr, parent,
                                        owner, 1);
                        if (ret < 0) {
-                               error("add_tree_backref failed: %s",
+                               error(
+                               "add_tree_backref failed (non-leaf block): %s",
                                      strerror(-ret));
                                continue;
                        }
@@ -8055,7 +8120,7 @@ static int delete_extent_records(struct btrfs_trans_handle *trans,
                if (found_key.type == BTRFS_EXTENT_ITEM_KEY ||
                    found_key.type == BTRFS_METADATA_ITEM_KEY) {
                        u64 bytes = (found_key.type == BTRFS_EXTENT_ITEM_KEY) ?
-                               found_key.offset : root->nodesize;
+                               found_key.offset : root->fs_info->nodesize;
 
                        ret = btrfs_update_block_group(trans, root, bytenr,
                                                       bytes, 0, 0);
@@ -8089,7 +8154,7 @@ static int record_extent(struct btrfs_trans_handle *trans,
 
        if (!back->is_data)
                rec->max_size = max_t(u64, rec->max_size,
-                                   info->extent_root->nodesize);
+                                   info->nodesize);
 
        if (!allocated) {
                u32 item_size = sizeof(*ei);
@@ -9719,7 +9784,7 @@ static int deal_root_from_list(struct list_head *list,
                rec = list_entry(list->next,
                                 struct root_item_record, list);
                last = 0;
-               buf = read_tree_block(root->fs_info->tree_root,
+               buf = read_tree_block(root->fs_info,
                                      rec->bytenr, rec->level_size, 0);
                if (!extent_buffer_uptodate(buf)) {
                        free_extent_buffer(buf);
@@ -9832,14 +9897,14 @@ again:
        level = btrfs_header_level(root1->node);
        ret = add_root_item_to_list(&normal_trees, root1->root_key.objectid,
                                    root1->node->start, 0, level, 0,
-                                   root1->nodesize, NULL);
+                                   root1->fs_info->nodesize, NULL);
        if (ret < 0)
                goto out;
        root1 = root->fs_info->chunk_root;
        level = btrfs_header_level(root1->node);
        ret = add_root_item_to_list(&normal_trees, root1->root_key.objectid,
                                    root1->node->start, 0, level, 0,
-                                   root1->nodesize, NULL);
+                                   root1->fs_info->nodesize, NULL);
        if (ret < 0)
                goto out;
        btrfs_init_path(&path);
@@ -9870,7 +9935,7 @@ again:
                        last_snapshot = btrfs_root_last_snapshot(&ri);
                        if (btrfs_disk_key_objectid(&ri.drop_progress) == 0) {
                                level = btrfs_root_level(&ri);
-                               level_size = root->nodesize;
+                               level_size = root->fs_info->nodesize;
                                ret = add_root_item_to_list(&normal_trees,
                                                found_key.objectid,
                                                btrfs_root_bytenr(&ri),
@@ -9880,7 +9945,7 @@ again:
                                        goto out;
                        } else {
                                level = btrfs_root_level(&ri);
-                               level_size = root->nodesize;
+                               level_size = root->fs_info->nodesize;
                                objectid = found_key.objectid;
                                btrfs_disk_key_to_cpu(&found_key,
                                                      &ri.drop_progress);
@@ -9960,6 +10025,8 @@ out:
        free_extent_cache_tree(&pending);
        free_extent_cache_tree(&reada);
        free_extent_cache_tree(&nodes);
+       free_root_item_list(&normal_trees);
+       free_root_item_list(&dropping_trees);
        return ret;
 loop:
        free_corrupt_blocks_tree(root->fs_info->corrupt_blocks);
@@ -10005,7 +10072,7 @@ static int check_tree_block_ref(struct btrfs_root *root,
        int slot;
        int skinny_level;
        int type;
-       u32 nodesize = root->nodesize;
+       u32 nodesize = root->fs_info->nodesize;
        u32 item_size;
        u64 offset;
        int tree_reloc_root = 0;
@@ -10190,20 +10257,20 @@ static int check_extent_data_item(struct btrfs_root *root,
        extent_num_bytes = btrfs_file_extent_num_bytes(eb, fi);
 
        /* Check unaligned disk_num_bytes and num_bytes */
-       if (!IS_ALIGNED(disk_num_bytes, root->sectorsize)) {
+       if (!IS_ALIGNED(disk_num_bytes, root->fs_info->sectorsize)) {
                error(
 "file extent [%llu, %llu] has unaligned disk num bytes: %llu, should be aligned to %u",
                        fi_key.objectid, fi_key.offset, disk_num_bytes,
-                       root->sectorsize);
+                       root->fs_info->sectorsize);
                err |= BYTES_UNALIGNED;
        } else {
                data_bytes_allocated += disk_num_bytes;
        }
-       if (!IS_ALIGNED(extent_num_bytes, root->sectorsize)) {
+       if (!IS_ALIGNED(extent_num_bytes, root->fs_info->sectorsize)) {
                error(
 "file extent [%llu, %llu] has unaligned num bytes: %llu, should be aligned to %u",
                        fi_key.objectid, fi_key.offset, extent_num_bytes,
-                       root->sectorsize);
+                       root->fs_info->sectorsize);
                err |= BYTES_UNALIGNED;
        } else {
                data_bytes_referenced += extent_num_bytes;
@@ -10217,10 +10284,8 @@ static int check_extent_data_item(struct btrfs_root *root,
        dbref_key.offset = btrfs_file_extent_disk_num_bytes(eb, fi);
 
        ret = btrfs_search_slot(NULL, extent_root, &dbref_key, &path, 0, 0);
-       if (ret) {
-               err |= BACKREF_MISSING;
-               goto error;
-       }
+       if (ret)
+               goto out;
 
        leaf = path.nodes[0];
        slot = path.slots[0];
@@ -10261,11 +10326,10 @@ static int check_extent_data_item(struct btrfs_root *root,
                ptr += btrfs_extent_inline_ref_size(type);
        }
 
-       /* Didn't found inlined data backref, try EXTENT_DATA_REF_KEY */
        if (!found_dbackref) {
                btrfs_release_path(&path);
 
-               btrfs_init_path(&path);
+               /* Didn't find inlined data backref, try EXTENT_DATA_REF_KEY */
                dbref_key.objectid = btrfs_file_extent_disk_bytenr(eb, fi);
                dbref_key.type = BTRFS_EXTENT_DATA_REF_KEY;
                dbref_key.offset = hash_extent_data_ref(root->objectid,
@@ -10273,13 +10337,32 @@ static int check_extent_data_item(struct btrfs_root *root,
 
                ret = btrfs_search_slot(NULL, root->fs_info->extent_root,
                                        &dbref_key, &path, 0, 0);
-               if (!ret)
+               if (!ret) {
+                       found_dbackref = 1;
+                       goto out;
+               }
+
+               btrfs_release_path(&path);
+
+               /*
+                * Neither inlined nor EXTENT_DATA_REF found, try
+                * SHARED_DATA_REF as last chance.
+                */
+               dbref_key.objectid = disk_bytenr;
+               dbref_key.type = BTRFS_SHARED_DATA_REF_KEY;
+               dbref_key.offset = eb->start;
+
+               ret = btrfs_search_slot(NULL, root->fs_info->extent_root,
+                                       &dbref_key, &path, 0, 0);
+               if (!ret) {
                        found_dbackref = 1;
+                       goto out;
+               }
        }
 
+out:
        if (!found_dbackref)
                err |= BACKREF_MISSING;
-error:
        btrfs_release_path(&path);
        if (err & BACKREF_MISSING) {
                error("data extent[%llu %llu] backref lost",
@@ -10347,7 +10430,7 @@ static int query_tree_block_level(struct btrfs_fs_info *fs_info, u64 bytenr)
        btrfs_release_path(&path);
 
        /* Get level from tree block as an alternative source */
-       eb = read_tree_block_fs_info(fs_info, bytenr, nodesize, transid);
+       eb = read_tree_block(fs_info, bytenr, nodesize, transid);
        if (!extent_buffer_uptodate(eb)) {
                free_extent_buffer(eb);
                return -EIO;
@@ -10400,7 +10483,7 @@ static int check_tree_block_backref(struct btrfs_fs_info *fs_info, u64 root_id,
        }
 
        /* Read out the tree block to get item/node key */
-       eb = read_tree_block(root, bytenr, root->nodesize, 0);
+       eb = read_tree_block(fs_info, bytenr, root->fs_info->nodesize, 0);
        if (!extent_buffer_uptodate(eb)) {
                err |= REFERENCER_MISSING;
                free_extent_buffer(eb);
@@ -10502,7 +10585,7 @@ static int check_shared_block_backref(struct btrfs_fs_info *fs_info,
        int found_parent = 0;
        int i;
 
-       eb = read_tree_block_fs_info(fs_info, parent, nodesize, 0);
+       eb = read_tree_block(fs_info, parent, nodesize, 0);
        if (!extent_buffer_uptodate(eb))
                goto out;
 
@@ -10656,7 +10739,7 @@ static int check_shared_data_backref(struct btrfs_fs_info *fs_info,
        int found_parent = 0;
        int i;
 
-       eb = read_tree_block_fs_info(fs_info, parent, nodesize, 0);
+       eb = read_tree_block(fs_info, parent, nodesize, 0);
        if (!extent_buffer_uptodate(eb))
                goto out;
 
@@ -10844,7 +10927,12 @@ static int check_dev_extent_item(struct btrfs_fs_info *fs_info,
 
        l = path.nodes[0];
        chunk = btrfs_item_ptr(l, path.slots[0], struct btrfs_chunk);
-       if (btrfs_chunk_length(l, chunk) != length)
+       ret = btrfs_check_chunk_valid(fs_info, l, chunk, path.slots[0],
+                                     chunk_key.offset);
+       if (ret < 0)
+               goto out;
+
+       if (btrfs_stripe_length(fs_info, l, chunk) != length)
                goto out;
 
        num_stripes = btrfs_chunk_num_stripes(l, chunk);
@@ -11082,11 +11170,10 @@ static int check_chunk_item(struct btrfs_fs_info *fs_info,
        struct btrfs_block_group_item *bi;
        struct btrfs_block_group_item bg_item;
        struct btrfs_dev_extent *ptr;
-       u32 sectorsize = btrfs_super_sectorsize(fs_info->super_copy);
        u64 length;
        u64 chunk_end;
+       u64 stripe_len;
        u64 type;
-       u64 profile;
        int num_stripes;
        u64 offset;
        u64 objectid;
@@ -11098,25 +11185,15 @@ static int check_chunk_item(struct btrfs_fs_info *fs_info,
        chunk = btrfs_item_ptr(eb, slot, struct btrfs_chunk);
        length = btrfs_chunk_length(eb, chunk);
        chunk_end = chunk_key.offset + length;
-       if (!IS_ALIGNED(length, sectorsize)) {
-               error("chunk[%llu %llu) not aligned to %u",
-                       chunk_key.offset, chunk_end, sectorsize);
-               err |= BYTES_UNALIGNED;
+       ret = btrfs_check_chunk_valid(fs_info, eb, chunk, slot,
+                                     chunk_key.offset);
+       if (ret < 0) {
+               error("chunk[%llu %llu) is invalid", chunk_key.offset,
+                       chunk_end);
+               err |= BYTES_UNALIGNED | UNKNOWN_TYPE;
                goto out;
        }
-
        type = btrfs_chunk_type(eb, chunk);
-       profile = type & BTRFS_BLOCK_GROUP_PROFILE_MASK;
-       if (!(type & BTRFS_BLOCK_GROUP_TYPE_MASK)) {
-               error("chunk[%llu %llu) has no chunk type",
-                       chunk_key.offset, chunk_end);
-               err |= UNKNOWN_TYPE;
-       }
-       if (profile && (profile & (profile - 1))) {
-               error("chunk[%llu %llu) multiple profiles detected: %llx",
-                       chunk_key.offset, chunk_end, profile);
-               err |= UNKNOWN_TYPE;
-       }
 
        bg_key.objectid = chunk_key.offset;
        bg_key.type = BTRFS_BLOCK_GROUP_ITEM_KEY;
@@ -11145,6 +11222,7 @@ static int check_chunk_item(struct btrfs_fs_info *fs_info,
        }
 
        num_stripes = btrfs_chunk_num_stripes(eb, chunk);
+       stripe_len = btrfs_stripe_length(fs_info, eb, chunk);
        for (i = 0; i < num_stripes; i++) {
                btrfs_release_path(&path);
                btrfs_init_path(&path);
@@ -11164,7 +11242,7 @@ static int check_chunk_item(struct btrfs_fs_info *fs_info,
                offset = btrfs_dev_extent_chunk_offset(leaf, ptr);
                if (objectid != chunk_key.objectid ||
                    offset != chunk_key.offset ||
-                   btrfs_dev_extent_length(leaf, ptr) != length)
+                   btrfs_dev_extent_length(leaf, ptr) != stripe_len)
                        goto not_match_dev;
                continue;
 not_match_dev:
@@ -11423,7 +11501,8 @@ static int traverse_tree_block(struct btrfs_root *root,
                 * As a btrfs tree has most 8 levels (0..7), so it's quite safe
                 * to call the function itself.
                 */
-               eb = read_tree_block(root, blocknr, root->nodesize, 0);
+               eb = read_tree_block(root->fs_info, blocknr,
+                               root->fs_info->nodesize, 0);
                if (extent_buffer_uptodate(eb)) {
                        ret = traverse_tree_block(root, eb);
                        err |= ret;
@@ -11514,7 +11593,7 @@ static int btrfs_fsck_reinit_root(struct btrfs_trans_handle *trans,
                goto init;
        }
        c = btrfs_alloc_free_block(trans, root,
-                                  root->nodesize,
+                                  root->fs_info->nodesize,
                                   root->root_key.objectid,
                                   &disk_key, level, 0, 0);
        if (IS_ERR(c)) {
@@ -11609,8 +11688,7 @@ static int pin_down_tree_blocks(struct btrfs_fs_info *fs_info,
                         * in, but for now this doesn't actually use the root so
                         * just pass in extent_root.
                         */
-                       tmp = read_tree_block(fs_info->extent_root, bytenr,
-                                             nodesize, 0);
+                       tmp = read_tree_block(fs_info, bytenr, nodesize, 0);
                        if (!extent_buffer_uptodate(tmp)) {
                                fprintf(stderr, "Error reading root block\n");
                                return -EIO;
@@ -11628,7 +11706,7 @@ static int pin_down_tree_blocks(struct btrfs_fs_info *fs_info,
                                continue;
                        }
 
-                       tmp = read_tree_block(fs_info->extent_root, bytenr,
+                       tmp = read_tree_block(fs_info, bytenr,
                                              nodesize, 0);
                        if (!extent_buffer_uptodate(tmp)) {
                                fprintf(stderr, "Error reading tree block\n");
@@ -12007,13 +12085,14 @@ static int populate_csum(struct btrfs_trans_handle *trans,
                         struct btrfs_root *csum_root, char *buf, u64 start,
                         u64 len)
 {
+       struct btrfs_fs_info *fs_info = csum_root->fs_info;
        u64 offset = 0;
        u64 sectorsize;
        int ret = 0;
 
        while (offset < len) {
-               sectorsize = csum_root->sectorsize;
-               ret = read_extent_data(csum_root, buf, start + offset,
+               sectorsize = fs_info->sectorsize;
+               ret = read_extent_data(fs_info, buf, start + offset,
                                       &sectorsize, 0);
                if (ret)
                        break;
@@ -12040,7 +12119,7 @@ static int fill_csum_tree_from_one_fs_root(struct btrfs_trans_handle *trans,
        int slot = 0;
        int ret = 0;
 
-       buf = malloc(cur_root->fs_info->csum_root->sectorsize);
+       buf = malloc(cur_root->fs_info->sectorsize);
        if (!buf)
                return -ENOMEM;
 
@@ -12172,7 +12251,7 @@ static int fill_csum_tree_from_extent(struct btrfs_trans_handle *trans,
                return ret;
        }
 
-       buf = malloc(csum_root->sectorsize);
+       buf = malloc(csum_root->fs_info->sectorsize);
        if (!buf) {
                btrfs_release_path(&path);
                return -ENOMEM;