Skip to content

Commit 7ef4951

Browse files
adam900710kdave
authored andcommitted
btrfs: Verify that every chunk has corresponding block group at mount time
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>
1 parent 514c7dc commit 7ef4951

File tree

1 file changed

+57
-1
lines changed

1 file changed

+57
-1
lines changed

fs/btrfs/extent-tree.c

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9844,6 +9844,62 @@ btrfs_create_block_group_cache(struct btrfs_fs_info *fs_info,
98449844
return cache;
98459845
}
98469846

9847+
9848+
/*
9849+
* Iterate all chunks and verify that each of them has the corresponding block
9850+
* group
9851+
*/
9852+
static int check_chunk_block_group_mappings(struct btrfs_fs_info *fs_info)
9853+
{
9854+
struct btrfs_mapping_tree *map_tree = &fs_info->mapping_tree;
9855+
struct extent_map *em;
9856+
struct btrfs_block_group_cache *bg;
9857+
u64 start = 0;
9858+
int ret = 0;
9859+
9860+
while (1) {
9861+
read_lock(&map_tree->map_tree.lock);
9862+
/*
9863+
* lookup_extent_mapping will return the first extent map
9864+
* intersecting the range, so setting @len to 1 is enough to
9865+
* get the first chunk.
9866+
*/
9867+
em = lookup_extent_mapping(&map_tree->map_tree, start, 1);
9868+
read_unlock(&map_tree->map_tree.lock);
9869+
if (!em)
9870+
break;
9871+
9872+
bg = btrfs_lookup_block_group(fs_info, em->start);
9873+
if (!bg) {
9874+
btrfs_err(fs_info,
9875+
"chunk start=%llu len=%llu doesn't have corresponding block group",
9876+
em->start, em->len);
9877+
ret = -EUCLEAN;
9878+
free_extent_map(em);
9879+
break;
9880+
}
9881+
if (bg->key.objectid != em->start ||
9882+
bg->key.offset != em->len ||
9883+
(bg->flags & BTRFS_BLOCK_GROUP_TYPE_MASK) !=
9884+
(em->map_lookup->type & BTRFS_BLOCK_GROUP_TYPE_MASK)) {
9885+
btrfs_err(fs_info,
9886+
"chunk start=%llu len=%llu flags=0x%llx doesn't match block group start=%llu len=%llu flags=0x%llx",
9887+
em->start, em->len,
9888+
em->map_lookup->type & BTRFS_BLOCK_GROUP_TYPE_MASK,
9889+
bg->key.objectid, bg->key.offset,
9890+
bg->flags & BTRFS_BLOCK_GROUP_TYPE_MASK);
9891+
ret = -EUCLEAN;
9892+
free_extent_map(em);
9893+
btrfs_put_block_group(bg);
9894+
break;
9895+
}
9896+
start = em->start + em->len;
9897+
free_extent_map(em);
9898+
btrfs_put_block_group(bg);
9899+
}
9900+
return ret;
9901+
}
9902+
98479903
int btrfs_read_block_groups(struct btrfs_fs_info *info)
98489904
{
98499905
struct btrfs_path *path;
@@ -10010,7 +10066,7 @@ int btrfs_read_block_groups(struct btrfs_fs_info *info)
1001010066

1001110067
btrfs_add_raid_kobjects(info);
1001210068
init_global_block_rsv(info);
10013-
ret = 0;
10069+
ret = check_chunk_block_group_mappings(info);
1001410070
error:
1001510071
btrfs_free_path(path);
1001610072
return ret;

0 commit comments

Comments
 (0)