diff options
author | Qu Wenruo <wqu@suse.com> | 2018-07-31 22:37:16 -0400 |
---|---|---|
committer | David Sterba <dsterba@suse.com> | 2018-08-06 07:13:03 -0400 |
commit | 514c7dca85a0bf40be984dab0b477403a6db901f (patch) | |
tree | 4a7209f5812949aeee3fe8a783b6d7bef8f95e7f | |
parent | 22d3151c2c4cb517a309154d1e828a28106508c7 (diff) |
btrfs: Check that each block group has corresponding chunk at mount time
A crafted btrfs image with incorrect chunk<->block group mapping will
trigger a lot of unexpected things as the mapping is essential.
Although the problem can be caught by block group item checker
added in "btrfs: tree-checker: Verify block_group_item", it's still not
sufficient. A sufficiently valid block group item can pass the check
added by the mentioned patch but could fail to match the existing chunk.
This patch will add extra block group -> chunk mapping check, to ensure
we have a completely matching (start, len, flags) chunk for each block
group at mount time.
Here we reuse the original helper find_first_block_group(), which is
already doing the basic bg -> chunk checks, adding further checks of the
start/len and type flags.
Link: https://bugzilla.kernel.org/show_bug.cgi?id=199837
Reported-by: Xu Wen <wen.xu@gatech.edu>
Signed-off-by: Qu Wenruo <wqu@suse.com>
Reviewed-by: Su Yue <suy.fnst@cn.fujitsu.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
-rw-r--r-- | fs/btrfs/extent-tree.c | 28 |
1 files changed, 27 insertions, 1 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 9e7b237b9547..54a0cfef5c5c 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -9532,6 +9532,8 @@ static int find_first_block_group(struct btrfs_fs_info *fs_info, | |||
9532 | int ret = 0; | 9532 | int ret = 0; |
9533 | struct btrfs_key found_key; | 9533 | struct btrfs_key found_key; |
9534 | struct extent_buffer *leaf; | 9534 | struct extent_buffer *leaf; |
9535 | struct btrfs_block_group_item bg; | ||
9536 | u64 flags; | ||
9535 | int slot; | 9537 | int slot; |
9536 | 9538 | ||
9537 | ret = btrfs_search_slot(NULL, root, key, path, 0, 0); | 9539 | ret = btrfs_search_slot(NULL, root, key, path, 0, 0); |
@@ -9566,8 +9568,32 @@ static int find_first_block_group(struct btrfs_fs_info *fs_info, | |||
9566 | "logical %llu len %llu found bg but no related chunk", | 9568 | "logical %llu len %llu found bg but no related chunk", |
9567 | found_key.objectid, found_key.offset); | 9569 | found_key.objectid, found_key.offset); |
9568 | ret = -ENOENT; | 9570 | ret = -ENOENT; |
9571 | } else if (em->start != found_key.objectid || | ||
9572 | em->len != found_key.offset) { | ||
9573 | btrfs_err(fs_info, | ||
9574 | "block group %llu len %llu mismatch with chunk %llu len %llu", | ||
9575 | found_key.objectid, found_key.offset, | ||
9576 | em->start, em->len); | ||
9577 | ret = -EUCLEAN; | ||
9569 | } else { | 9578 | } else { |
9570 | ret = 0; | 9579 | read_extent_buffer(leaf, &bg, |
9580 | btrfs_item_ptr_offset(leaf, slot), | ||
9581 | sizeof(bg)); | ||
9582 | flags = btrfs_block_group_flags(&bg) & | ||
9583 | BTRFS_BLOCK_GROUP_TYPE_MASK; | ||
9584 | |||
9585 | if (flags != (em->map_lookup->type & | ||
9586 | BTRFS_BLOCK_GROUP_TYPE_MASK)) { | ||
9587 | btrfs_err(fs_info, | ||
9588 | "block group %llu len %llu type flags 0x%llx mismatch with chunk type flags 0x%llx", | ||
9589 | found_key.objectid, | ||
9590 | found_key.offset, flags, | ||
9591 | (BTRFS_BLOCK_GROUP_TYPE_MASK & | ||
9592 | em->map_lookup->type)); | ||
9593 | ret = -EUCLEAN; | ||
9594 | } else { | ||
9595 | ret = 0; | ||
9596 | } | ||
9571 | } | 9597 | } |
9572 | free_extent_map(em); | 9598 | free_extent_map(em); |
9573 | goto out; | 9599 | goto out; |