lkml.org 
[lkml]   [2018]   [Dec]   [6]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.9 066/101] btrfs: Verify that every chunk has corresponding block group at mount time
    Date
    4.9-stable review patch.  If anyone has any objections, please let me know.

    ------------------

    From: Qu Wenruo <wqu@suse.com>

    commit 7ef49515fa6727cb4b6f2f5b0ffbc5fc20a9f8c6 upstream.

    If a crafted image has missing block group items, it could cause
    unexpected behavior and breaks the assumption of 1:1 chunk<->block group
    mapping.

    Although we have the block group -> chunk mapping check, we still need
    chunk -> block group mapping check.

    This patch will do extra check to ensure each chunk has its
    corresponding block group.

    Link: https://bugzilla.kernel.org/show_bug.cgi?id=199847
    Reported-by: Xu Wen <wen.xu@gatech.edu>
    Signed-off-by: Qu Wenruo <wqu@suse.com>
    Reviewed-by: Gu Jinxiang <gujx@cn.fujitsu.com>
    Reviewed-by: David Sterba <dsterba@suse.com>
    Signed-off-by: David Sterba <dsterba@suse.com>
    [bwh: Backported to 4.9: adjust context]
    Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    ---
    fs/btrfs/extent-tree.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++-
    1 file changed, 57 insertions(+), 1 deletion(-)

    --- a/fs/btrfs/extent-tree.c
    +++ b/fs/btrfs/extent-tree.c
    @@ -10159,6 +10159,62 @@ btrfs_create_block_group_cache(struct bt
    return cache;
    }

    +
    +/*
    + * Iterate all chunks and verify that each of them has the corresponding block
    + * group
    + */
    +static int check_chunk_block_group_mappings(struct btrfs_fs_info *fs_info)
    +{
    + struct btrfs_mapping_tree *map_tree = &fs_info->mapping_tree;
    + struct extent_map *em;
    + struct btrfs_block_group_cache *bg;
    + u64 start = 0;
    + int ret = 0;
    +
    + while (1) {
    + read_lock(&map_tree->map_tree.lock);
    + /*
    + * lookup_extent_mapping will return the first extent map
    + * intersecting the range, so setting @len to 1 is enough to
    + * get the first chunk.
    + */
    + em = lookup_extent_mapping(&map_tree->map_tree, start, 1);
    + read_unlock(&map_tree->map_tree.lock);
    + if (!em)
    + break;
    +
    + bg = btrfs_lookup_block_group(fs_info, em->start);
    + if (!bg) {
    + btrfs_err(fs_info,
    + "chunk start=%llu len=%llu doesn't have corresponding block group",
    + em->start, em->len);
    + ret = -EUCLEAN;
    + free_extent_map(em);
    + break;
    + }
    + if (bg->key.objectid != em->start ||
    + bg->key.offset != em->len ||
    + (bg->flags & BTRFS_BLOCK_GROUP_TYPE_MASK) !=
    + (em->map_lookup->type & BTRFS_BLOCK_GROUP_TYPE_MASK)) {
    + btrfs_err(fs_info,
    +"chunk start=%llu len=%llu flags=0x%llx doesn't match block group start=%llu len=%llu flags=0x%llx",
    + em->start, em->len,
    + em->map_lookup->type & BTRFS_BLOCK_GROUP_TYPE_MASK,
    + bg->key.objectid, bg->key.offset,
    + bg->flags & BTRFS_BLOCK_GROUP_TYPE_MASK);
    + ret = -EUCLEAN;
    + free_extent_map(em);
    + btrfs_put_block_group(bg);
    + break;
    + }
    + start = em->start + em->len;
    + free_extent_map(em);
    + btrfs_put_block_group(bg);
    + }
    + return ret;
    +}
    +
    int btrfs_read_block_groups(struct btrfs_root *root)
    {
    struct btrfs_path *path;
    @@ -10343,7 +10399,7 @@ int btrfs_read_block_groups(struct btrfs
    }

    init_global_block_rsv(info);
    - ret = 0;
    + ret = check_chunk_block_group_mappings(info);
    error:
    btrfs_free_path(path);
    return ret;

    \
     
     \ /
      Last update: 2018-12-06 15:51    [W:4.084 / U:0.048 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site