On 2019/10/17 上午11:23, Anand Jain wrote: > On 10/8/19 12:49 PM, Qu Wenruo wrote: >> This patch does the following refactor: >> - Refactor parameter from @root to @fs_info >> >> - Refactor the large loop body into another function >>    Now we have a helper function, read_one_block_group(), to handle >>    block group cache and space info related routine. >> >> - Refactor the return value >>    Even we have the code handling ret > 0 from find_first_block_group(), >>    it never works, as when there is no more block group, >>    find_first_block_group() just return -ENOENT other than 1. > > >  Can it be separated into patches? My concern is as it alters the return >  value of the rescue command. So we shall have clarity of a discrete >  patch to blame. Otherwise I agree its a good change. No problem. What about 3 patches split by the mentioned 3 refactors? > > >>    This is super confusing, it's almost a mircle it even works. >> >> Signed-off-by: Qu Wenruo >> --- >>   ctree.h       |   2 +- >>   disk-io.c     |   9 ++- >>   extent-tree.c | 160 ++++++++++++++++++++++++++++---------------------- >>   3 files changed, 97 insertions(+), 74 deletions(-) >> >> diff --git a/ctree.h b/ctree.h >> index 8c7b3cb40151..2899de358613 100644 >> --- a/ctree.h >> +++ b/ctree.h >> @@ -2550,7 +2550,7 @@ int update_space_info(struct btrfs_fs_info >> *info, u64 flags, >>                 u64 total_bytes, u64 bytes_used, >>                 struct btrfs_space_info **space_info); >>   int btrfs_free_block_groups(struct btrfs_fs_info *info); >> -int btrfs_read_block_groups(struct btrfs_root *root); >> +int btrfs_read_block_groups(struct btrfs_fs_info *info); >>   struct btrfs_block_group_cache * >>   btrfs_add_block_group(struct btrfs_fs_info *fs_info, u64 bytes_used, >> u64 type, >>                 u64 chunk_offset, u64 size); >> diff --git a/disk-io.c b/disk-io.c >> index be44eead5cef..8978f0cb60c7 100644 >> --- a/disk-io.c >> +++ b/disk-io.c >> @@ -983,14 +983,17 @@ int btrfs_setup_all_roots(struct btrfs_fs_info >> *fs_info, u64 root_tree_bytenr, >>       fs_info->last_trans_committed = generation; >>       if (extent_buffer_uptodate(fs_info->extent_root->node) && >>           !(flags & OPEN_CTREE_NO_BLOCK_GROUPS)) { >> -        ret = btrfs_read_block_groups(fs_info->tree_root); >> +        ret = btrfs_read_block_groups(fs_info); >>           /* >>            * If we don't find any blockgroups (ENOENT) we're either >>            * restoring or creating the filesystem, where it's expected, >>            * anything else is error >>            */ >> -        if (ret != -ENOENT) >> -            return -EIO; >> +        if (ret < 0 && ret != -ENOENT) { >> +            errno = -ret; >> +            error("failed to read block groups: %m"); >> +            return ret; >> +        } >>       } > > > As mentioned this alters the rescue command semantics as show below. > Earlier we had only -EIO as error now its much more and accurate > which is good. fstests is fine but anything else? > > cmd_rescue_chunk_recover() >   btrfs_recover_chunk_tree() >     open_ctree_with_broken_chunk() >       btrfs_setup_all_roots() I'm not sure if I got the point. Although btrfs_setup_all_roots() get called in above call chain, it doesn't have any special handling of -EIO or others. It just reads the extent tree root. Would you mind to explain a little more? Thanks, Qu > > Thanks, Anand > >>       key.objectid = BTRFS_FS_TREE_OBJECTID; >> diff --git a/extent-tree.c b/extent-tree.c >> index 19d1ea0df570..9713d627764c 100644 >> --- a/extent-tree.c >> +++ b/extent-tree.c >> @@ -2607,6 +2607,13 @@ int btrfs_free_block_groups(struct >> btrfs_fs_info *info) >>       return 0; >>   } >>   +/* >> + * Find a block group which starts >= @key->objectid in extent tree. >> + * >> + * Return 0 for found >> + * Retrun >0 for not found >> + * Return <0 for error >> + */ >>   static int find_first_block_group(struct btrfs_root *root, >>           struct btrfs_path *path, struct btrfs_key *key) >>   { >> @@ -2636,36 +2643,95 @@ static int find_first_block_group(struct >> btrfs_root *root, >>               return 0; >>           path->slots[0]++; >>       } >> -    ret = -ENOENT; >> +    ret = 1; >>   error: >>       return ret; >>   } >>   -int btrfs_read_block_groups(struct btrfs_root *root) >> +/* >> + * Helper function to read out one BLOCK_GROUP_ITEM and insert it into >> + * block group cache. >> + * >> + * Return 0 if nothing wrong (either insert the bg cache or skip 0 >> sized bg) >> + * Return <0 for error. >> + */ >> +static int read_one_block_group(struct btrfs_fs_info *fs_info, >> +                 struct btrfs_path *path) >>   { >> -    struct btrfs_path *path; >> -    int ret; >> -    int bit; >> -    struct btrfs_block_group_cache *cache; >> -    struct btrfs_fs_info *info = root->fs_info; >> +    struct extent_io_tree *block_group_cache = >> &fs_info->block_group_cache; >> +    struct extent_buffer *leaf = path->nodes[0]; >>       struct btrfs_space_info *space_info; >> -    struct extent_io_tree *block_group_cache; >> +    struct btrfs_block_group_cache *cache; >>       struct btrfs_key key; >> -    struct btrfs_key found_key; >> -    struct extent_buffer *leaf; >> +    int slot = path->slots[0]; >> +    int bit = 0; >> +    int ret; >>   -    block_group_cache = &info->block_group_cache; >> +    btrfs_item_key_to_cpu(leaf, &key, slot); >> +    ASSERT(key.type == BTRFS_BLOCK_GROUP_ITEM_KEY); >> + >> +    /* >> +     * Skip 0 sized block group, don't insert them into block >> +     * group cache tree, as its length is 0, it won't get >> +     * freed at close_ctree() time. >> +     */ >> +    if (key.offset == 0) >> +        return 0; >> + >> +    cache = kzalloc(sizeof(*cache), GFP_NOFS); >> +    if (!cache) >> +        return -ENOMEM; >> +    read_extent_buffer(leaf, &cache->item, >> +               btrfs_item_ptr_offset(leaf, slot), >> +               sizeof(cache->item)); >> +    memcpy(&cache->key, &key, sizeof(key)); >> +    cache->cached = 0; >> +    cache->pinned = 0; >> +    cache->flags = btrfs_block_group_flags(&cache->item); >> +    if (cache->flags & BTRFS_BLOCK_GROUP_DATA) { >> +        bit = BLOCK_GROUP_DATA; >> +    } else if (cache->flags & BTRFS_BLOCK_GROUP_SYSTEM) { >> +        bit = BLOCK_GROUP_SYSTEM; >> +    } else if (cache->flags & BTRFS_BLOCK_GROUP_METADATA) { >> +        bit = BLOCK_GROUP_METADATA; >> +    } >> +    set_avail_alloc_bits(fs_info, cache->flags); >> +    if (btrfs_chunk_readonly(fs_info, cache->key.objectid)) >> +        cache->ro = 1; >> +    exclude_super_stripes(fs_info, cache); >> + >> +    ret = update_space_info(fs_info, cache->flags, cache->key.offset, >> +                btrfs_block_group_used(&cache->item), >> +                &space_info); >> +    if (ret < 0) { >> +        free(cache); >> +        return ret; >> +    } >> +    cache->space_info = space_info; >> + >> +    set_extent_bits(block_group_cache, cache->key.objectid, >> +            cache->key.objectid + cache->key.offset - 1, >> +            bit | EXTENT_LOCKED); >> +    set_state_private(block_group_cache, cache->key.objectid, >> +              (unsigned long)cache); >> +    return 0; >> +} >>   -    root = info->extent_root; >> +int btrfs_read_block_groups(struct btrfs_fs_info *fs_info) >> +{ >> +    struct btrfs_path path; >> +    struct btrfs_root *root; >> +    int ret; >> +    struct btrfs_key key; >> + >> +    root = fs_info->extent_root; >>       key.objectid = 0; >>       key.offset = 0; >>       key.type = BTRFS_BLOCK_GROUP_ITEM_KEY; >> -    path = btrfs_alloc_path(); >> -    if (!path) >> -        return -ENOMEM; >> +    btrfs_init_path(&path); >>         while(1) { >> -        ret = find_first_block_group(root, path, &key); >> +        ret = find_first_block_group(root, &path, &key); >>           if (ret > 0) { >>               ret = 0; >>               goto error; >> @@ -2673,67 +2739,21 @@ int btrfs_read_block_groups(struct btrfs_root >> *root) >>           if (ret != 0) { >>               goto error; >>           } >> -        leaf = path->nodes[0]; >> -        btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); >> +        btrfs_item_key_to_cpu(path.nodes[0], &key, path.slots[0]); >>   -        cache = kzalloc(sizeof(*cache), GFP_NOFS); >> -        if (!cache) { >> -            ret = -ENOMEM; >> +        ret = read_one_block_group(fs_info, &path); >> +        if (ret < 0) >>               goto error; >> -        } >>   -        read_extent_buffer(leaf, &cache->item, >> -                   btrfs_item_ptr_offset(leaf, path->slots[0]), >> -                   sizeof(cache->item)); >> -        memcpy(&cache->key, &found_key, sizeof(found_key)); >> -        cache->cached = 0; >> -        cache->pinned = 0; >> -        key.objectid = found_key.objectid + found_key.offset; >> -        if (found_key.offset == 0) >> +        if (key.offset == 0) >>               key.objectid++; >> -        btrfs_release_path(path); >> - >> -        /* >> -         * Skip 0 sized block group, don't insert them into block >> -         * group cache tree, as its length is 0, it won't get >> -         * freed at close_ctree() time. >> -         */ >> -        if (found_key.offset == 0) { >> -            free(cache); >> -            continue; >> -        } >> - >> -        cache->flags = btrfs_block_group_flags(&cache->item); >> -        bit = 0; >> -        if (cache->flags & BTRFS_BLOCK_GROUP_DATA) { >> -            bit = BLOCK_GROUP_DATA; >> -        } else if (cache->flags & BTRFS_BLOCK_GROUP_SYSTEM) { >> -            bit = BLOCK_GROUP_SYSTEM; >> -        } else if (cache->flags & BTRFS_BLOCK_GROUP_METADATA) { >> -            bit = BLOCK_GROUP_METADATA; >> -        } >> -        set_avail_alloc_bits(info, cache->flags); >> -        if (btrfs_chunk_readonly(info, cache->key.objectid)) >> -            cache->ro = 1; >> - >> -        exclude_super_stripes(info, cache); >> - >> -        ret = update_space_info(info, cache->flags, found_key.offset, >> -                    btrfs_block_group_used(&cache->item), >> -                    &space_info); >> -        BUG_ON(ret); >> -        cache->space_info = space_info; >> - >> -        /* use EXTENT_LOCKED to prevent merging */ >> -        set_extent_bits(block_group_cache, found_key.objectid, >> -                found_key.objectid + found_key.offset - 1, >> -                bit | EXTENT_LOCKED); >> -        set_state_private(block_group_cache, found_key.objectid, >> -                  (unsigned long)cache); >> +        else >> +            key.objectid = key.objectid + key.offset; >> +        btrfs_release_path(&path); >>       } >>       ret = 0; >>   error: >> -    btrfs_free_path(path); >> +    btrfs_release_path(&path); >>       return ret; >>   } >>   >