diff options
| -rw-r--r-- | fs/btrfs/disk-io.c | 11 | ||||
| -rw-r--r-- | fs/btrfs/hash.c | 5 | ||||
| -rw-r--r-- | fs/btrfs/hash.h | 1 | ||||
| -rw-r--r-- | fs/btrfs/super.c | 5 | ||||
| -rw-r--r-- | fs/btrfs/volumes.c | 109 | ||||
| -rw-r--r-- | include/uapi/linux/btrfs.h | 2 |
6 files changed, 115 insertions, 18 deletions
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index c3764ddb2a46..1142127f6e5e 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
| @@ -4133,6 +4133,17 @@ static int btrfs_check_super_valid(struct btrfs_fs_info *fs_info, | |||
| 4133 | * Hint to catch really bogus numbers, bitflips or so, more exact checks are | 4133 | * Hint to catch really bogus numbers, bitflips or so, more exact checks are |
| 4134 | * done later | 4134 | * done later |
| 4135 | */ | 4135 | */ |
| 4136 | if (btrfs_super_bytes_used(sb) < 6 * btrfs_super_nodesize(sb)) { | ||
| 4137 | btrfs_err(fs_info, "bytes_used is too small %llu", | ||
| 4138 | btrfs_super_bytes_used(sb)); | ||
| 4139 | ret = -EINVAL; | ||
| 4140 | } | ||
| 4141 | if (!is_power_of_2(btrfs_super_stripesize(sb)) || | ||
| 4142 | btrfs_super_stripesize(sb) != sectorsize) { | ||
| 4143 | btrfs_err(fs_info, "invalid stripesize %u", | ||
| 4144 | btrfs_super_stripesize(sb)); | ||
| 4145 | ret = -EINVAL; | ||
| 4146 | } | ||
| 4136 | if (btrfs_super_num_devices(sb) > (1UL << 31)) | 4147 | if (btrfs_super_num_devices(sb) > (1UL << 31)) |
| 4137 | printk(KERN_WARNING "BTRFS: suspicious number of devices: %llu\n", | 4148 | printk(KERN_WARNING "BTRFS: suspicious number of devices: %llu\n", |
| 4138 | btrfs_super_num_devices(sb)); | 4149 | btrfs_super_num_devices(sb)); |
diff --git a/fs/btrfs/hash.c b/fs/btrfs/hash.c index aae520b2aee5..a97fdc156a03 100644 --- a/fs/btrfs/hash.c +++ b/fs/btrfs/hash.c | |||
| @@ -24,6 +24,11 @@ int __init btrfs_hash_init(void) | |||
| 24 | return PTR_ERR_OR_ZERO(tfm); | 24 | return PTR_ERR_OR_ZERO(tfm); |
| 25 | } | 25 | } |
| 26 | 26 | ||
| 27 | const char* btrfs_crc32c_impl(void) | ||
| 28 | { | ||
| 29 | return crypto_tfm_alg_driver_name(crypto_shash_tfm(tfm)); | ||
| 30 | } | ||
| 31 | |||
| 27 | void btrfs_hash_exit(void) | 32 | void btrfs_hash_exit(void) |
| 28 | { | 33 | { |
| 29 | crypto_free_shash(tfm); | 34 | crypto_free_shash(tfm); |
diff --git a/fs/btrfs/hash.h b/fs/btrfs/hash.h index 118a2316e5d3..c3a2ec554361 100644 --- a/fs/btrfs/hash.h +++ b/fs/btrfs/hash.h | |||
| @@ -22,6 +22,7 @@ | |||
| 22 | int __init btrfs_hash_init(void); | 22 | int __init btrfs_hash_init(void); |
| 23 | 23 | ||
| 24 | void btrfs_hash_exit(void); | 24 | void btrfs_hash_exit(void); |
| 25 | const char* btrfs_crc32c_impl(void); | ||
| 25 | 26 | ||
| 26 | u32 btrfs_crc32c(u32 crc, const void *address, unsigned int length); | 27 | u32 btrfs_crc32c(u32 crc, const void *address, unsigned int length); |
| 27 | 28 | ||
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index c49d7ae69617..4339b6613f19 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c | |||
| @@ -2303,7 +2303,7 @@ static void btrfs_interface_exit(void) | |||
| 2303 | 2303 | ||
| 2304 | static void btrfs_print_mod_info(void) | 2304 | static void btrfs_print_mod_info(void) |
| 2305 | { | 2305 | { |
| 2306 | printk(KERN_INFO "Btrfs loaded" | 2306 | printk(KERN_INFO "Btrfs loaded, crc32c=%s" |
| 2307 | #ifdef CONFIG_BTRFS_DEBUG | 2307 | #ifdef CONFIG_BTRFS_DEBUG |
| 2308 | ", debug=on" | 2308 | ", debug=on" |
| 2309 | #endif | 2309 | #endif |
| @@ -2313,7 +2313,8 @@ static void btrfs_print_mod_info(void) | |||
| 2313 | #ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY | 2313 | #ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY |
| 2314 | ", integrity-checker=on" | 2314 | ", integrity-checker=on" |
| 2315 | #endif | 2315 | #endif |
| 2316 | "\n"); | 2316 | "\n", |
| 2317 | btrfs_crc32c_impl()); | ||
| 2317 | } | 2318 | } |
| 2318 | 2319 | ||
| 2319 | static int btrfs_run_sanity_tests(void) | 2320 | static int btrfs_run_sanity_tests(void) |
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 765aabd9145f..fcbda4341f7d 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); |
| @@ -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); |
diff --git a/include/uapi/linux/btrfs.h b/include/uapi/linux/btrfs.h index 23c6960e94a4..2bdd1e3e7007 100644 --- a/include/uapi/linux/btrfs.h +++ b/include/uapi/linux/btrfs.h | |||
| @@ -118,7 +118,7 @@ struct btrfs_ioctl_vol_args_v2 { | |||
| 118 | }; | 118 | }; |
| 119 | union { | 119 | union { |
| 120 | char name[BTRFS_SUBVOL_NAME_MAX + 1]; | 120 | char name[BTRFS_SUBVOL_NAME_MAX + 1]; |
| 121 | u64 devid; | 121 | __u64 devid; |
| 122 | }; | 122 | }; |
| 123 | }; | 123 | }; |
| 124 | 124 | ||
