aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorQu Wenruo <wqu@suse.com>2018-07-31 22:37:17 -0400
committerDavid Sterba <dsterba@suse.com>2018-08-06 07:13:03 -0400
commit7ef49515fa6727cb4b6f2f5b0ffbc5fc20a9f8c6 (patch)
tree2013a3d439113c58479b799561e07dfb5d072b02
parent514c7dca85a0bf40be984dab0b477403a6db901f (diff)
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>
-rw-r--r--fs/btrfs/extent-tree.c58
1 files changed, 57 insertions, 1 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 54a0cfef5c5c..de6f75f5547b 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -9844,6 +9844,62 @@ btrfs_create_block_group_cache(struct btrfs_fs_info *fs_info,
9844 return cache; 9844 return cache;
9845} 9845}
9846 9846
9847
9848/*
9849 * Iterate all chunks and verify that each of them has the corresponding block
9850 * group
9851 */
9852static 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
9847int btrfs_read_block_groups(struct btrfs_fs_info *info) 9903int btrfs_read_block_groups(struct btrfs_fs_info *info)
9848{ 9904{
9849 struct btrfs_path *path; 9905 struct btrfs_path *path;
@@ -10010,7 +10066,7 @@ int btrfs_read_block_groups(struct btrfs_fs_info *info)
10010 10066
10011 btrfs_add_raid_kobjects(info); 10067 btrfs_add_raid_kobjects(info);
10012 init_global_block_rsv(info); 10068 init_global_block_rsv(info);
10013 ret = 0; 10069 ret = check_chunk_block_group_mappings(info);
10014error: 10070error:
10015 btrfs_free_path(path); 10071 btrfs_free_path(path);
10016 return ret; 10072 return ret;