diff options
author | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2016-06-20 11:25:44 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2016-06-20 11:25:44 -0400 |
commit | af52739b922f656eb1f39016fabaabe4baeda2e2 (patch) | |
tree | 79a7aa810d0493cd0cf4adebac26d37f12e8b545 /fs/btrfs/volumes.c | |
parent | 25ed6a5e97809129a1bc852b6b5c7d03baa112c4 (diff) | |
parent | 33688abb2802ff3a230bd2441f765477b94cc89e (diff) |
Merge 4.7-rc4 into staging-next
We want the fixes in here, and we can resolve a merge issue in
drivers/iio/industrialio-trigger.c
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'fs/btrfs/volumes.c')
-rw-r--r-- | fs/btrfs/volumes.c | 113 |
1 files changed, 96 insertions, 17 deletions
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index da9e0036a864..2f631b58ae00 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c | |||
@@ -4241,6 +4241,7 @@ int btrfs_create_uuid_tree(struct btrfs_fs_info *fs_info) | |||
4241 | if (IS_ERR(uuid_root)) { | 4241 | if (IS_ERR(uuid_root)) { |
4242 | ret = PTR_ERR(uuid_root); | 4242 | ret = PTR_ERR(uuid_root); |
4243 | btrfs_abort_transaction(trans, tree_root, ret); | 4243 | btrfs_abort_transaction(trans, tree_root, ret); |
4244 | btrfs_end_transaction(trans, tree_root); | ||
4244 | return ret; | 4245 | return ret; |
4245 | } | 4246 | } |
4246 | 4247 | ||
@@ -6258,27 +6259,23 @@ struct btrfs_device *btrfs_alloc_device(struct btrfs_fs_info *fs_info, | |||
6258 | return dev; | 6259 | return dev; |
6259 | } | 6260 | } |
6260 | 6261 | ||
6261 | static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key, | 6262 | /* Return -EIO if any error, otherwise return 0. */ |
6262 | struct extent_buffer *leaf, | 6263 | static int btrfs_check_chunk_valid(struct btrfs_root *root, |
6263 | struct btrfs_chunk *chunk) | 6264 | struct extent_buffer *leaf, |
6265 | struct btrfs_chunk *chunk, u64 logical) | ||
6264 | { | 6266 | { |
6265 | struct btrfs_mapping_tree *map_tree = &root->fs_info->mapping_tree; | ||
6266 | struct map_lookup *map; | ||
6267 | struct extent_map *em; | ||
6268 | u64 logical; | ||
6269 | u64 length; | 6267 | u64 length; |
6270 | u64 stripe_len; | 6268 | u64 stripe_len; |
6271 | u64 devid; | 6269 | u16 num_stripes; |
6272 | u8 uuid[BTRFS_UUID_SIZE]; | 6270 | u16 sub_stripes; |
6273 | int num_stripes; | 6271 | u64 type; |
6274 | int ret; | ||
6275 | int i; | ||
6276 | 6272 | ||
6277 | logical = key->offset; | ||
6278 | length = btrfs_chunk_length(leaf, chunk); | 6273 | length = btrfs_chunk_length(leaf, chunk); |
6279 | stripe_len = btrfs_chunk_stripe_len(leaf, chunk); | 6274 | stripe_len = btrfs_chunk_stripe_len(leaf, chunk); |
6280 | num_stripes = btrfs_chunk_num_stripes(leaf, chunk); | 6275 | num_stripes = btrfs_chunk_num_stripes(leaf, chunk); |
6281 | /* Validation check */ | 6276 | sub_stripes = btrfs_chunk_sub_stripes(leaf, chunk); |
6277 | type = btrfs_chunk_type(leaf, chunk); | ||
6278 | |||
6282 | if (!num_stripes) { | 6279 | if (!num_stripes) { |
6283 | btrfs_err(root->fs_info, "invalid chunk num_stripes: %u", | 6280 | btrfs_err(root->fs_info, "invalid chunk num_stripes: %u", |
6284 | num_stripes); | 6281 | num_stripes); |
@@ -6289,6 +6286,11 @@ static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key, | |||
6289 | "invalid chunk logical %llu", logical); | 6286 | "invalid chunk logical %llu", logical); |
6290 | return -EIO; | 6287 | return -EIO; |
6291 | } | 6288 | } |
6289 | if (btrfs_chunk_sector_size(leaf, chunk) != root->sectorsize) { | ||
6290 | btrfs_err(root->fs_info, "invalid chunk sectorsize %u", | ||
6291 | btrfs_chunk_sector_size(leaf, chunk)); | ||
6292 | return -EIO; | ||
6293 | } | ||
6292 | if (!length || !IS_ALIGNED(length, root->sectorsize)) { | 6294 | if (!length || !IS_ALIGNED(length, root->sectorsize)) { |
6293 | btrfs_err(root->fs_info, | 6295 | btrfs_err(root->fs_info, |
6294 | "invalid chunk length %llu", length); | 6296 | "invalid chunk length %llu", length); |
@@ -6300,13 +6302,54 @@ static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key, | |||
6300 | return -EIO; | 6302 | return -EIO; |
6301 | } | 6303 | } |
6302 | if (~(BTRFS_BLOCK_GROUP_TYPE_MASK | BTRFS_BLOCK_GROUP_PROFILE_MASK) & | 6304 | if (~(BTRFS_BLOCK_GROUP_TYPE_MASK | BTRFS_BLOCK_GROUP_PROFILE_MASK) & |
6303 | btrfs_chunk_type(leaf, chunk)) { | 6305 | type) { |
6304 | btrfs_err(root->fs_info, "unrecognized chunk type: %llu", | 6306 | btrfs_err(root->fs_info, "unrecognized chunk type: %llu", |
6305 | ~(BTRFS_BLOCK_GROUP_TYPE_MASK | | 6307 | ~(BTRFS_BLOCK_GROUP_TYPE_MASK | |
6306 | BTRFS_BLOCK_GROUP_PROFILE_MASK) & | 6308 | BTRFS_BLOCK_GROUP_PROFILE_MASK) & |
6307 | btrfs_chunk_type(leaf, chunk)); | 6309 | btrfs_chunk_type(leaf, chunk)); |
6308 | return -EIO; | 6310 | return -EIO; |
6309 | } | 6311 | } |
6312 | if ((type & BTRFS_BLOCK_GROUP_RAID10 && sub_stripes != 2) || | ||
6313 | (type & BTRFS_BLOCK_GROUP_RAID1 && num_stripes < 1) || | ||
6314 | (type & BTRFS_BLOCK_GROUP_RAID5 && num_stripes < 2) || | ||
6315 | (type & BTRFS_BLOCK_GROUP_RAID6 && num_stripes < 3) || | ||
6316 | (type & BTRFS_BLOCK_GROUP_DUP && num_stripes > 2) || | ||
6317 | ((type & BTRFS_BLOCK_GROUP_PROFILE_MASK) == 0 && | ||
6318 | num_stripes != 1)) { | ||
6319 | btrfs_err(root->fs_info, | ||
6320 | "invalid num_stripes:sub_stripes %u:%u for profile %llu", | ||
6321 | num_stripes, sub_stripes, | ||
6322 | type & BTRFS_BLOCK_GROUP_PROFILE_MASK); | ||
6323 | return -EIO; | ||
6324 | } | ||
6325 | |||
6326 | return 0; | ||
6327 | } | ||
6328 | |||
6329 | static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key, | ||
6330 | struct extent_buffer *leaf, | ||
6331 | struct btrfs_chunk *chunk) | ||
6332 | { | ||
6333 | struct btrfs_mapping_tree *map_tree = &root->fs_info->mapping_tree; | ||
6334 | struct map_lookup *map; | ||
6335 | struct extent_map *em; | ||
6336 | u64 logical; | ||
6337 | u64 length; | ||
6338 | u64 stripe_len; | ||
6339 | u64 devid; | ||
6340 | u8 uuid[BTRFS_UUID_SIZE]; | ||
6341 | int num_stripes; | ||
6342 | int ret; | ||
6343 | int i; | ||
6344 | |||
6345 | logical = key->offset; | ||
6346 | length = btrfs_chunk_length(leaf, chunk); | ||
6347 | stripe_len = btrfs_chunk_stripe_len(leaf, chunk); | ||
6348 | num_stripes = btrfs_chunk_num_stripes(leaf, chunk); | ||
6349 | |||
6350 | ret = btrfs_check_chunk_valid(root, leaf, chunk, logical); | ||
6351 | if (ret) | ||
6352 | return ret; | ||
6310 | 6353 | ||
6311 | read_lock(&map_tree->map_tree.lock); | 6354 | read_lock(&map_tree->map_tree.lock); |
6312 | em = lookup_extent_mapping(&map_tree->map_tree, logical, 1); | 6355 | em = lookup_extent_mapping(&map_tree->map_tree, logical, 1); |
@@ -6554,6 +6597,7 @@ int btrfs_read_sys_array(struct btrfs_root *root) | |||
6554 | u32 array_size; | 6597 | u32 array_size; |
6555 | u32 len = 0; | 6598 | u32 len = 0; |
6556 | u32 cur_offset; | 6599 | u32 cur_offset; |
6600 | u64 type; | ||
6557 | struct btrfs_key key; | 6601 | struct btrfs_key key; |
6558 | 6602 | ||
6559 | ASSERT(BTRFS_SUPER_INFO_SIZE <= root->nodesize); | 6603 | ASSERT(BTRFS_SUPER_INFO_SIZE <= root->nodesize); |
@@ -6563,8 +6607,8 @@ int btrfs_read_sys_array(struct btrfs_root *root) | |||
6563 | * overallocate but we can keep it as-is, only the first page is used. | 6607 | * overallocate but we can keep it as-is, only the first page is used. |
6564 | */ | 6608 | */ |
6565 | sb = btrfs_find_create_tree_block(root, BTRFS_SUPER_INFO_OFFSET); | 6609 | sb = btrfs_find_create_tree_block(root, BTRFS_SUPER_INFO_OFFSET); |
6566 | if (!sb) | 6610 | if (IS_ERR(sb)) |
6567 | return -ENOMEM; | 6611 | return PTR_ERR(sb); |
6568 | set_extent_buffer_uptodate(sb); | 6612 | set_extent_buffer_uptodate(sb); |
6569 | btrfs_set_buffer_lockdep_class(root->root_key.objectid, sb, 0); | 6613 | btrfs_set_buffer_lockdep_class(root->root_key.objectid, sb, 0); |
6570 | /* | 6614 | /* |
@@ -6620,6 +6664,15 @@ int btrfs_read_sys_array(struct btrfs_root *root) | |||
6620 | break; | 6664 | break; |
6621 | } | 6665 | } |
6622 | 6666 | ||
6667 | type = btrfs_chunk_type(sb, chunk); | ||
6668 | if ((type & BTRFS_BLOCK_GROUP_SYSTEM) == 0) { | ||
6669 | btrfs_err(root->fs_info, | ||
6670 | "invalid chunk type %llu in sys_array at offset %u", | ||
6671 | type, cur_offset); | ||
6672 | ret = -EIO; | ||
6673 | break; | ||
6674 | } | ||
6675 | |||
6623 | len = btrfs_chunk_item_size(num_stripes); | 6676 | len = btrfs_chunk_item_size(num_stripes); |
6624 | if (cur_offset + len > array_size) | 6677 | if (cur_offset + len > array_size) |
6625 | goto out_short_read; | 6678 | goto out_short_read; |
@@ -6638,12 +6691,14 @@ int btrfs_read_sys_array(struct btrfs_root *root) | |||
6638 | sb_array_offset += len; | 6691 | sb_array_offset += len; |
6639 | cur_offset += len; | 6692 | cur_offset += len; |
6640 | } | 6693 | } |
6694 | clear_extent_buffer_uptodate(sb); | ||
6641 | free_extent_buffer_stale(sb); | 6695 | free_extent_buffer_stale(sb); |
6642 | return ret; | 6696 | return ret; |
6643 | 6697 | ||
6644 | out_short_read: | 6698 | out_short_read: |
6645 | printk(KERN_ERR "BTRFS: sys_array too short to read %u bytes at offset %u\n", | 6699 | printk(KERN_ERR "BTRFS: sys_array too short to read %u bytes at offset %u\n", |
6646 | len, cur_offset); | 6700 | len, cur_offset); |
6701 | clear_extent_buffer_uptodate(sb); | ||
6647 | free_extent_buffer_stale(sb); | 6702 | free_extent_buffer_stale(sb); |
6648 | return -EIO; | 6703 | return -EIO; |
6649 | } | 6704 | } |
@@ -6656,6 +6711,7 @@ int btrfs_read_chunk_tree(struct btrfs_root *root) | |||
6656 | struct btrfs_key found_key; | 6711 | struct btrfs_key found_key; |
6657 | int ret; | 6712 | int ret; |
6658 | int slot; | 6713 | int slot; |
6714 | u64 total_dev = 0; | ||
6659 | 6715 | ||
6660 | root = root->fs_info->chunk_root; | 6716 | root = root->fs_info->chunk_root; |
6661 | 6717 | ||
@@ -6697,6 +6753,7 @@ int btrfs_read_chunk_tree(struct btrfs_root *root) | |||
6697 | ret = read_one_dev(root, leaf, dev_item); | 6753 | ret = read_one_dev(root, leaf, dev_item); |
6698 | if (ret) | 6754 | if (ret) |
6699 | goto error; | 6755 | goto error; |
6756 | total_dev++; | ||
6700 | } else if (found_key.type == BTRFS_CHUNK_ITEM_KEY) { | 6757 | } else if (found_key.type == BTRFS_CHUNK_ITEM_KEY) { |
6701 | struct btrfs_chunk *chunk; | 6758 | struct btrfs_chunk *chunk; |
6702 | chunk = btrfs_item_ptr(leaf, slot, struct btrfs_chunk); | 6759 | chunk = btrfs_item_ptr(leaf, slot, struct btrfs_chunk); |
@@ -6706,6 +6763,28 @@ int btrfs_read_chunk_tree(struct btrfs_root *root) | |||
6706 | } | 6763 | } |
6707 | path->slots[0]++; | 6764 | path->slots[0]++; |
6708 | } | 6765 | } |
6766 | |||
6767 | /* | ||
6768 | * After loading chunk tree, we've got all device information, | ||
6769 | * do another round of validation checks. | ||
6770 | */ | ||
6771 | if (total_dev != root->fs_info->fs_devices->total_devices) { | ||
6772 | btrfs_err(root->fs_info, | ||
6773 | "super_num_devices %llu mismatch with num_devices %llu found here", | ||
6774 | btrfs_super_num_devices(root->fs_info->super_copy), | ||
6775 | total_dev); | ||
6776 | ret = -EINVAL; | ||
6777 | goto error; | ||
6778 | } | ||
6779 | if (btrfs_super_total_bytes(root->fs_info->super_copy) < | ||
6780 | root->fs_info->fs_devices->total_rw_bytes) { | ||
6781 | btrfs_err(root->fs_info, | ||
6782 | "super_total_bytes %llu mismatch with fs_devices total_rw_bytes %llu", | ||
6783 | btrfs_super_total_bytes(root->fs_info->super_copy), | ||
6784 | root->fs_info->fs_devices->total_rw_bytes); | ||
6785 | ret = -EINVAL; | ||
6786 | goto error; | ||
6787 | } | ||
6709 | ret = 0; | 6788 | ret = 0; |
6710 | error: | 6789 | error: |
6711 | unlock_chunks(root); | 6790 | unlock_chunks(root); |