Loading fs/btrfs/disk-io.c +11 −0 Original line number Diff line number Diff line Loading @@ -4133,6 +4133,17 @@ static int btrfs_check_super_valid(struct btrfs_fs_info *fs_info, * Hint to catch really bogus numbers, bitflips or so, more exact checks are * done later */ if (btrfs_super_bytes_used(sb) < 6 * btrfs_super_nodesize(sb)) { btrfs_err(fs_info, "bytes_used is too small %llu", btrfs_super_bytes_used(sb)); ret = -EINVAL; } if (!is_power_of_2(btrfs_super_stripesize(sb)) || btrfs_super_stripesize(sb) != sectorsize) { btrfs_err(fs_info, "invalid stripesize %u", btrfs_super_stripesize(sb)); ret = -EINVAL; } if (btrfs_super_num_devices(sb) > (1UL << 31)) printk(KERN_WARNING "BTRFS: suspicious number of devices: %llu\n", btrfs_super_num_devices(sb)); Loading fs/btrfs/hash.c +5 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,11 @@ int __init btrfs_hash_init(void) return PTR_ERR_OR_ZERO(tfm); } const char* btrfs_crc32c_impl(void) { return crypto_tfm_alg_driver_name(crypto_shash_tfm(tfm)); } void btrfs_hash_exit(void) { crypto_free_shash(tfm); Loading fs/btrfs/hash.h +1 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ int __init btrfs_hash_init(void); void btrfs_hash_exit(void); const char* btrfs_crc32c_impl(void); u32 btrfs_crc32c(u32 crc, const void *address, unsigned int length); Loading fs/btrfs/super.c +3 −2 Original line number Diff line number Diff line Loading @@ -2303,7 +2303,7 @@ static void btrfs_interface_exit(void) static void btrfs_print_mod_info(void) { printk(KERN_INFO "Btrfs loaded" printk(KERN_INFO "Btrfs loaded, crc32c=%s" #ifdef CONFIG_BTRFS_DEBUG ", debug=on" #endif Loading @@ -2313,7 +2313,8 @@ static void btrfs_print_mod_info(void) #ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY ", integrity-checker=on" #endif "\n"); "\n", btrfs_crc32c_impl()); } static int btrfs_run_sanity_tests(void) Loading fs/btrfs/volumes.c +94 −15 Original line number Diff line number Diff line Loading @@ -4241,6 +4241,7 @@ int btrfs_create_uuid_tree(struct btrfs_fs_info *fs_info) if (IS_ERR(uuid_root)) { ret = PTR_ERR(uuid_root); btrfs_abort_transaction(trans, tree_root, ret); btrfs_end_transaction(trans, tree_root); return ret; } Loading Loading @@ -6258,27 +6259,23 @@ struct btrfs_device *btrfs_alloc_device(struct btrfs_fs_info *fs_info, return dev; } static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key, /* Return -EIO if any error, otherwise return 0. */ static int btrfs_check_chunk_valid(struct btrfs_root *root, struct extent_buffer *leaf, struct btrfs_chunk *chunk) struct btrfs_chunk *chunk, u64 logical) { struct btrfs_mapping_tree *map_tree = &root->fs_info->mapping_tree; struct map_lookup *map; struct extent_map *em; u64 logical; u64 length; u64 stripe_len; u64 devid; u8 uuid[BTRFS_UUID_SIZE]; int num_stripes; int ret; int i; u16 num_stripes; u16 sub_stripes; u64 type; logical = key->offset; length = btrfs_chunk_length(leaf, chunk); stripe_len = btrfs_chunk_stripe_len(leaf, chunk); num_stripes = btrfs_chunk_num_stripes(leaf, chunk); /* Validation check */ sub_stripes = btrfs_chunk_sub_stripes(leaf, chunk); type = btrfs_chunk_type(leaf, chunk); if (!num_stripes) { btrfs_err(root->fs_info, "invalid chunk num_stripes: %u", num_stripes); Loading @@ -6289,6 +6286,11 @@ static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key, "invalid chunk logical %llu", logical); return -EIO; } if (btrfs_chunk_sector_size(leaf, chunk) != root->sectorsize) { btrfs_err(root->fs_info, "invalid chunk sectorsize %u", btrfs_chunk_sector_size(leaf, chunk)); return -EIO; } if (!length || !IS_ALIGNED(length, root->sectorsize)) { btrfs_err(root->fs_info, "invalid chunk length %llu", length); Loading @@ -6300,13 +6302,54 @@ static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key, return -EIO; } if (~(BTRFS_BLOCK_GROUP_TYPE_MASK | BTRFS_BLOCK_GROUP_PROFILE_MASK) & btrfs_chunk_type(leaf, chunk)) { type) { btrfs_err(root->fs_info, "unrecognized chunk type: %llu", ~(BTRFS_BLOCK_GROUP_TYPE_MASK | BTRFS_BLOCK_GROUP_PROFILE_MASK) & btrfs_chunk_type(leaf, chunk)); return -EIO; } if ((type & BTRFS_BLOCK_GROUP_RAID10 && sub_stripes != 2) || (type & BTRFS_BLOCK_GROUP_RAID1 && num_stripes < 1) || (type & BTRFS_BLOCK_GROUP_RAID5 && num_stripes < 2) || (type & BTRFS_BLOCK_GROUP_RAID6 && num_stripes < 3) || (type & BTRFS_BLOCK_GROUP_DUP && num_stripes > 2) || ((type & BTRFS_BLOCK_GROUP_PROFILE_MASK) == 0 && num_stripes != 1)) { btrfs_err(root->fs_info, "invalid num_stripes:sub_stripes %u:%u for profile %llu", num_stripes, sub_stripes, type & BTRFS_BLOCK_GROUP_PROFILE_MASK); return -EIO; } return 0; } static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key, struct extent_buffer *leaf, struct btrfs_chunk *chunk) { struct btrfs_mapping_tree *map_tree = &root->fs_info->mapping_tree; struct map_lookup *map; struct extent_map *em; u64 logical; u64 length; u64 stripe_len; u64 devid; u8 uuid[BTRFS_UUID_SIZE]; int num_stripes; int ret; int i; logical = key->offset; length = btrfs_chunk_length(leaf, chunk); stripe_len = btrfs_chunk_stripe_len(leaf, chunk); num_stripes = btrfs_chunk_num_stripes(leaf, chunk); ret = btrfs_check_chunk_valid(root, leaf, chunk, logical); if (ret) return ret; read_lock(&map_tree->map_tree.lock); em = lookup_extent_mapping(&map_tree->map_tree, logical, 1); Loading Loading @@ -6554,6 +6597,7 @@ int btrfs_read_sys_array(struct btrfs_root *root) u32 array_size; u32 len = 0; u32 cur_offset; u64 type; struct btrfs_key key; ASSERT(BTRFS_SUPER_INFO_SIZE <= root->nodesize); Loading Loading @@ -6620,6 +6664,15 @@ int btrfs_read_sys_array(struct btrfs_root *root) break; } type = btrfs_chunk_type(sb, chunk); if ((type & BTRFS_BLOCK_GROUP_SYSTEM) == 0) { btrfs_err(root->fs_info, "invalid chunk type %llu in sys_array at offset %u", type, cur_offset); ret = -EIO; break; } len = btrfs_chunk_item_size(num_stripes); if (cur_offset + len > array_size) goto out_short_read; Loading @@ -6638,12 +6691,14 @@ int btrfs_read_sys_array(struct btrfs_root *root) sb_array_offset += len; cur_offset += len; } clear_extent_buffer_uptodate(sb); free_extent_buffer_stale(sb); return ret; out_short_read: printk(KERN_ERR "BTRFS: sys_array too short to read %u bytes at offset %u\n", len, cur_offset); clear_extent_buffer_uptodate(sb); free_extent_buffer_stale(sb); return -EIO; } Loading @@ -6656,6 +6711,7 @@ int btrfs_read_chunk_tree(struct btrfs_root *root) struct btrfs_key found_key; int ret; int slot; u64 total_dev = 0; root = root->fs_info->chunk_root; Loading Loading @@ -6697,6 +6753,7 @@ int btrfs_read_chunk_tree(struct btrfs_root *root) ret = read_one_dev(root, leaf, dev_item); if (ret) goto error; total_dev++; } else if (found_key.type == BTRFS_CHUNK_ITEM_KEY) { struct btrfs_chunk *chunk; chunk = btrfs_item_ptr(leaf, slot, struct btrfs_chunk); Loading @@ -6706,6 +6763,28 @@ int btrfs_read_chunk_tree(struct btrfs_root *root) } path->slots[0]++; } /* * After loading chunk tree, we've got all device information, * do another round of validation checks. */ if (total_dev != root->fs_info->fs_devices->total_devices) { btrfs_err(root->fs_info, "super_num_devices %llu mismatch with num_devices %llu found here", btrfs_super_num_devices(root->fs_info->super_copy), total_dev); ret = -EINVAL; goto error; } if (btrfs_super_total_bytes(root->fs_info->super_copy) < root->fs_info->fs_devices->total_rw_bytes) { btrfs_err(root->fs_info, "super_total_bytes %llu mismatch with fs_devices total_rw_bytes %llu", btrfs_super_total_bytes(root->fs_info->super_copy), root->fs_info->fs_devices->total_rw_bytes); ret = -EINVAL; goto error; } ret = 0; error: unlock_chunks(root); Loading Loading
fs/btrfs/disk-io.c +11 −0 Original line number Diff line number Diff line Loading @@ -4133,6 +4133,17 @@ static int btrfs_check_super_valid(struct btrfs_fs_info *fs_info, * Hint to catch really bogus numbers, bitflips or so, more exact checks are * done later */ if (btrfs_super_bytes_used(sb) < 6 * btrfs_super_nodesize(sb)) { btrfs_err(fs_info, "bytes_used is too small %llu", btrfs_super_bytes_used(sb)); ret = -EINVAL; } if (!is_power_of_2(btrfs_super_stripesize(sb)) || btrfs_super_stripesize(sb) != sectorsize) { btrfs_err(fs_info, "invalid stripesize %u", btrfs_super_stripesize(sb)); ret = -EINVAL; } if (btrfs_super_num_devices(sb) > (1UL << 31)) printk(KERN_WARNING "BTRFS: suspicious number of devices: %llu\n", btrfs_super_num_devices(sb)); Loading
fs/btrfs/hash.c +5 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,11 @@ int __init btrfs_hash_init(void) return PTR_ERR_OR_ZERO(tfm); } const char* btrfs_crc32c_impl(void) { return crypto_tfm_alg_driver_name(crypto_shash_tfm(tfm)); } void btrfs_hash_exit(void) { crypto_free_shash(tfm); Loading
fs/btrfs/hash.h +1 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ int __init btrfs_hash_init(void); void btrfs_hash_exit(void); const char* btrfs_crc32c_impl(void); u32 btrfs_crc32c(u32 crc, const void *address, unsigned int length); Loading
fs/btrfs/super.c +3 −2 Original line number Diff line number Diff line Loading @@ -2303,7 +2303,7 @@ static void btrfs_interface_exit(void) static void btrfs_print_mod_info(void) { printk(KERN_INFO "Btrfs loaded" printk(KERN_INFO "Btrfs loaded, crc32c=%s" #ifdef CONFIG_BTRFS_DEBUG ", debug=on" #endif Loading @@ -2313,7 +2313,8 @@ static void btrfs_print_mod_info(void) #ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY ", integrity-checker=on" #endif "\n"); "\n", btrfs_crc32c_impl()); } static int btrfs_run_sanity_tests(void) Loading
fs/btrfs/volumes.c +94 −15 Original line number Diff line number Diff line Loading @@ -4241,6 +4241,7 @@ int btrfs_create_uuid_tree(struct btrfs_fs_info *fs_info) if (IS_ERR(uuid_root)) { ret = PTR_ERR(uuid_root); btrfs_abort_transaction(trans, tree_root, ret); btrfs_end_transaction(trans, tree_root); return ret; } Loading Loading @@ -6258,27 +6259,23 @@ struct btrfs_device *btrfs_alloc_device(struct btrfs_fs_info *fs_info, return dev; } static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key, /* Return -EIO if any error, otherwise return 0. */ static int btrfs_check_chunk_valid(struct btrfs_root *root, struct extent_buffer *leaf, struct btrfs_chunk *chunk) struct btrfs_chunk *chunk, u64 logical) { struct btrfs_mapping_tree *map_tree = &root->fs_info->mapping_tree; struct map_lookup *map; struct extent_map *em; u64 logical; u64 length; u64 stripe_len; u64 devid; u8 uuid[BTRFS_UUID_SIZE]; int num_stripes; int ret; int i; u16 num_stripes; u16 sub_stripes; u64 type; logical = key->offset; length = btrfs_chunk_length(leaf, chunk); stripe_len = btrfs_chunk_stripe_len(leaf, chunk); num_stripes = btrfs_chunk_num_stripes(leaf, chunk); /* Validation check */ sub_stripes = btrfs_chunk_sub_stripes(leaf, chunk); type = btrfs_chunk_type(leaf, chunk); if (!num_stripes) { btrfs_err(root->fs_info, "invalid chunk num_stripes: %u", num_stripes); Loading @@ -6289,6 +6286,11 @@ static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key, "invalid chunk logical %llu", logical); return -EIO; } if (btrfs_chunk_sector_size(leaf, chunk) != root->sectorsize) { btrfs_err(root->fs_info, "invalid chunk sectorsize %u", btrfs_chunk_sector_size(leaf, chunk)); return -EIO; } if (!length || !IS_ALIGNED(length, root->sectorsize)) { btrfs_err(root->fs_info, "invalid chunk length %llu", length); Loading @@ -6300,13 +6302,54 @@ static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key, return -EIO; } if (~(BTRFS_BLOCK_GROUP_TYPE_MASK | BTRFS_BLOCK_GROUP_PROFILE_MASK) & btrfs_chunk_type(leaf, chunk)) { type) { btrfs_err(root->fs_info, "unrecognized chunk type: %llu", ~(BTRFS_BLOCK_GROUP_TYPE_MASK | BTRFS_BLOCK_GROUP_PROFILE_MASK) & btrfs_chunk_type(leaf, chunk)); return -EIO; } if ((type & BTRFS_BLOCK_GROUP_RAID10 && sub_stripes != 2) || (type & BTRFS_BLOCK_GROUP_RAID1 && num_stripes < 1) || (type & BTRFS_BLOCK_GROUP_RAID5 && num_stripes < 2) || (type & BTRFS_BLOCK_GROUP_RAID6 && num_stripes < 3) || (type & BTRFS_BLOCK_GROUP_DUP && num_stripes > 2) || ((type & BTRFS_BLOCK_GROUP_PROFILE_MASK) == 0 && num_stripes != 1)) { btrfs_err(root->fs_info, "invalid num_stripes:sub_stripes %u:%u for profile %llu", num_stripes, sub_stripes, type & BTRFS_BLOCK_GROUP_PROFILE_MASK); return -EIO; } return 0; } static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key, struct extent_buffer *leaf, struct btrfs_chunk *chunk) { struct btrfs_mapping_tree *map_tree = &root->fs_info->mapping_tree; struct map_lookup *map; struct extent_map *em; u64 logical; u64 length; u64 stripe_len; u64 devid; u8 uuid[BTRFS_UUID_SIZE]; int num_stripes; int ret; int i; logical = key->offset; length = btrfs_chunk_length(leaf, chunk); stripe_len = btrfs_chunk_stripe_len(leaf, chunk); num_stripes = btrfs_chunk_num_stripes(leaf, chunk); ret = btrfs_check_chunk_valid(root, leaf, chunk, logical); if (ret) return ret; read_lock(&map_tree->map_tree.lock); em = lookup_extent_mapping(&map_tree->map_tree, logical, 1); Loading Loading @@ -6554,6 +6597,7 @@ int btrfs_read_sys_array(struct btrfs_root *root) u32 array_size; u32 len = 0; u32 cur_offset; u64 type; struct btrfs_key key; ASSERT(BTRFS_SUPER_INFO_SIZE <= root->nodesize); Loading Loading @@ -6620,6 +6664,15 @@ int btrfs_read_sys_array(struct btrfs_root *root) break; } type = btrfs_chunk_type(sb, chunk); if ((type & BTRFS_BLOCK_GROUP_SYSTEM) == 0) { btrfs_err(root->fs_info, "invalid chunk type %llu in sys_array at offset %u", type, cur_offset); ret = -EIO; break; } len = btrfs_chunk_item_size(num_stripes); if (cur_offset + len > array_size) goto out_short_read; Loading @@ -6638,12 +6691,14 @@ int btrfs_read_sys_array(struct btrfs_root *root) sb_array_offset += len; cur_offset += len; } clear_extent_buffer_uptodate(sb); free_extent_buffer_stale(sb); return ret; out_short_read: printk(KERN_ERR "BTRFS: sys_array too short to read %u bytes at offset %u\n", len, cur_offset); clear_extent_buffer_uptodate(sb); free_extent_buffer_stale(sb); return -EIO; } Loading @@ -6656,6 +6711,7 @@ int btrfs_read_chunk_tree(struct btrfs_root *root) struct btrfs_key found_key; int ret; int slot; u64 total_dev = 0; root = root->fs_info->chunk_root; Loading Loading @@ -6697,6 +6753,7 @@ int btrfs_read_chunk_tree(struct btrfs_root *root) ret = read_one_dev(root, leaf, dev_item); if (ret) goto error; total_dev++; } else if (found_key.type == BTRFS_CHUNK_ITEM_KEY) { struct btrfs_chunk *chunk; chunk = btrfs_item_ptr(leaf, slot, struct btrfs_chunk); Loading @@ -6706,6 +6763,28 @@ int btrfs_read_chunk_tree(struct btrfs_root *root) } path->slots[0]++; } /* * After loading chunk tree, we've got all device information, * do another round of validation checks. */ if (total_dev != root->fs_info->fs_devices->total_devices) { btrfs_err(root->fs_info, "super_num_devices %llu mismatch with num_devices %llu found here", btrfs_super_num_devices(root->fs_info->super_copy), total_dev); ret = -EINVAL; goto error; } if (btrfs_super_total_bytes(root->fs_info->super_copy) < root->fs_info->fs_devices->total_rw_bytes) { btrfs_err(root->fs_info, "super_total_bytes %llu mismatch with fs_devices total_rw_bytes %llu", btrfs_super_total_bytes(root->fs_info->super_copy), root->fs_info->fs_devices->total_rw_bytes); ret = -EINVAL; goto error; } ret = 0; error: unlock_chunks(root); Loading