aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/btrfs/volumes.c82
1 files changed, 67 insertions, 15 deletions
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index fd5c9e69894a..74507b05061b 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -6251,27 +6251,23 @@ struct btrfs_device *btrfs_alloc_device(struct btrfs_fs_info *fs_info,
6251 return dev; 6251 return dev;
6252} 6252}
6253 6253
6254static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key, 6254/* Return -EIO if any error, otherwise return 0. */
6255 struct extent_buffer *leaf, 6255static int btrfs_check_chunk_valid(struct btrfs_root *root,
6256 struct btrfs_chunk *chunk) 6256 struct extent_buffer *leaf,
6257 struct btrfs_chunk *chunk, u64 logical)
6257{ 6258{
6258 struct btrfs_mapping_tree *map_tree = &root->fs_info->mapping_tree;
6259 struct map_lookup *map;
6260 struct extent_map *em;
6261 u64 logical;
6262 u64 length; 6259 u64 length;
6263 u64 stripe_len; 6260 u64 stripe_len;
6264 u64 devid; 6261 u16 num_stripes;
6265 u8 uuid[BTRFS_UUID_SIZE]; 6262 u16 sub_stripes;
6266 int num_stripes; 6263 u64 type;
6267 int ret;
6268 int i;
6269 6264
6270 logical = key->offset;
6271 length = btrfs_chunk_length(leaf, chunk); 6265 length = btrfs_chunk_length(leaf, chunk);
6272 stripe_len = btrfs_chunk_stripe_len(leaf, chunk); 6266 stripe_len = btrfs_chunk_stripe_len(leaf, chunk);
6273 num_stripes = btrfs_chunk_num_stripes(leaf, chunk); 6267 num_stripes = btrfs_chunk_num_stripes(leaf, chunk);
6274 /* Validation check */ 6268 sub_stripes = btrfs_chunk_sub_stripes(leaf, chunk);
6269 type = btrfs_chunk_type(leaf, chunk);
6270
6275 if (!num_stripes) { 6271 if (!num_stripes) {
6276 btrfs_err(root->fs_info, "invalid chunk num_stripes: %u", 6272 btrfs_err(root->fs_info, "invalid chunk num_stripes: %u",
6277 num_stripes); 6273 num_stripes);
@@ -6282,6 +6278,11 @@ static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key,
6282 "invalid chunk logical %llu", logical); 6278 "invalid chunk logical %llu", logical);
6283 return -EIO; 6279 return -EIO;
6284 } 6280 }
6281 if (btrfs_chunk_sector_size(leaf, chunk) != root->sectorsize) {
6282 btrfs_err(root->fs_info, "invalid chunk sectorsize %u",
6283 btrfs_chunk_sector_size(leaf, chunk));
6284 return -EIO;
6285 }
6285 if (!length || !IS_ALIGNED(length, root->sectorsize)) { 6286 if (!length || !IS_ALIGNED(length, root->sectorsize)) {
6286 btrfs_err(root->fs_info, 6287 btrfs_err(root->fs_info,
6287 "invalid chunk length %llu", length); 6288 "invalid chunk length %llu", length);
@@ -6293,13 +6294,54 @@ static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key,
6293 return -EIO; 6294 return -EIO;
6294 } 6295 }
6295 if (~(BTRFS_BLOCK_GROUP_TYPE_MASK | BTRFS_BLOCK_GROUP_PROFILE_MASK) & 6296 if (~(BTRFS_BLOCK_GROUP_TYPE_MASK | BTRFS_BLOCK_GROUP_PROFILE_MASK) &
6296 btrfs_chunk_type(leaf, chunk)) { 6297 type) {
6297 btrfs_err(root->fs_info, "unrecognized chunk type: %llu", 6298 btrfs_err(root->fs_info, "unrecognized chunk type: %llu",
6298 ~(BTRFS_BLOCK_GROUP_TYPE_MASK | 6299 ~(BTRFS_BLOCK_GROUP_TYPE_MASK |
6299 BTRFS_BLOCK_GROUP_PROFILE_MASK) & 6300 BTRFS_BLOCK_GROUP_PROFILE_MASK) &
6300 btrfs_chunk_type(leaf, chunk)); 6301 btrfs_chunk_type(leaf, chunk));
6301 return -EIO; 6302 return -EIO;
6302 } 6303 }
6304 if ((type & BTRFS_BLOCK_GROUP_RAID10 && sub_stripes != 2) ||
6305 (type & BTRFS_BLOCK_GROUP_RAID1 && num_stripes < 1) ||
6306 (type & BTRFS_BLOCK_GROUP_RAID5 && num_stripes < 2) ||
6307 (type & BTRFS_BLOCK_GROUP_RAID6 && num_stripes < 3) ||
6308 (type & BTRFS_BLOCK_GROUP_DUP && num_stripes > 2) ||
6309 ((type & BTRFS_BLOCK_GROUP_PROFILE_MASK) == 0 &&
6310 num_stripes != 1)) {
6311 btrfs_err(root->fs_info,
6312 "invalid num_stripes:sub_stripes %u:%u for profile %llu",
6313 num_stripes, sub_stripes,
6314 type & BTRFS_BLOCK_GROUP_PROFILE_MASK);
6315 return -EIO;
6316 }
6317
6318 return 0;
6319}
6320
6321static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key,
6322 struct extent_buffer *leaf,
6323 struct btrfs_chunk *chunk)
6324{
6325 struct btrfs_mapping_tree *map_tree = &root->fs_info->mapping_tree;
6326 struct map_lookup *map;
6327 struct extent_map *em;
6328 u64 logical;
6329 u64 length;
6330 u64 stripe_len;
6331 u64 devid;
6332 u8 uuid[BTRFS_UUID_SIZE];
6333 int num_stripes;
6334 int ret;
6335 int i;
6336
6337 logical = key->offset;
6338 length = btrfs_chunk_length(leaf, chunk);
6339 stripe_len = btrfs_chunk_stripe_len(leaf, chunk);
6340 num_stripes = btrfs_chunk_num_stripes(leaf, chunk);
6341
6342 ret = btrfs_check_chunk_valid(root, leaf, chunk, logical);
6343 if (ret)
6344 return ret;
6303 6345
6304 read_lock(&map_tree->map_tree.lock); 6346 read_lock(&map_tree->map_tree.lock);
6305 em = lookup_extent_mapping(&map_tree->map_tree, logical, 1); 6347 em = lookup_extent_mapping(&map_tree->map_tree, logical, 1);
@@ -6547,6 +6589,7 @@ int btrfs_read_sys_array(struct btrfs_root *root)
6547 u32 array_size; 6589 u32 array_size;
6548 u32 len = 0; 6590 u32 len = 0;
6549 u32 cur_offset; 6591 u32 cur_offset;
6592 u64 type;
6550 struct btrfs_key key; 6593 struct btrfs_key key;
6551 6594
6552 ASSERT(BTRFS_SUPER_INFO_SIZE <= root->nodesize); 6595 ASSERT(BTRFS_SUPER_INFO_SIZE <= root->nodesize);
@@ -6613,6 +6656,15 @@ int btrfs_read_sys_array(struct btrfs_root *root)
6613 break; 6656 break;
6614 } 6657 }
6615 6658
6659 type = btrfs_chunk_type(sb, chunk);
6660 if ((type & BTRFS_BLOCK_GROUP_SYSTEM) == 0) {
6661 btrfs_err(root->fs_info,
6662 "invalid chunk type %llu in sys_array at offset %u",
6663 type, cur_offset);
6664 ret = -EIO;
6665 break;
6666 }
6667
6616 len = btrfs_chunk_item_size(num_stripes); 6668 len = btrfs_chunk_item_size(num_stripes);
6617 if (cur_offset + len > array_size) 6669 if (cur_offset + len > array_size)
6618 goto out_short_read; 6670 goto out_short_read;