@@ -4241,6 +4241,7 @@ int btrfs_create_uuid_tree(struct btrfs_fs_info *fs_info)
4241
4241
if (IS_ERR (uuid_root )) {
4242
4242
ret = PTR_ERR (uuid_root );
4243
4243
btrfs_abort_transaction (trans , tree_root , ret );
4244
+ btrfs_end_transaction (trans , tree_root );
4244
4245
return ret ;
4245
4246
}
4246
4247
@@ -6258,27 +6259,23 @@ struct btrfs_device *btrfs_alloc_device(struct btrfs_fs_info *fs_info,
6258
6259
return dev ;
6259
6260
}
6260
6261
6261
- static int read_one_chunk (struct btrfs_root * root , struct btrfs_key * key ,
6262
- struct extent_buffer * leaf ,
6263
- struct btrfs_chunk * chunk )
6262
+ /* Return -EIO if any error, otherwise return 0. */
6263
+ static int btrfs_check_chunk_valid (struct btrfs_root * root ,
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
6267
u64 length ;
6270
6268
u64 stripe_len ;
6271
- u64 devid ;
6272
- u8 uuid [BTRFS_UUID_SIZE ];
6273
- int num_stripes ;
6274
- int ret ;
6275
- int i ;
6269
+ u16 num_stripes ;
6270
+ u16 sub_stripes ;
6271
+ u64 type ;
6276
6272
6277
- logical = key -> offset ;
6278
6273
length = btrfs_chunk_length (leaf , chunk );
6279
6274
stripe_len = btrfs_chunk_stripe_len (leaf , chunk );
6280
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
6279
if (!num_stripes ) {
6283
6280
btrfs_err (root -> fs_info , "invalid chunk num_stripes: %u" ,
6284
6281
num_stripes );
@@ -6289,6 +6286,11 @@ static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key,
6289
6286
"invalid chunk logical %llu" , logical );
6290
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
6294
if (!length || !IS_ALIGNED (length , root -> sectorsize )) {
6293
6295
btrfs_err (root -> fs_info ,
6294
6296
"invalid chunk length %llu" , length );
@@ -6300,13 +6302,54 @@ static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key,
6300
6302
return - EIO ;
6301
6303
}
6302
6304
if (~(BTRFS_BLOCK_GROUP_TYPE_MASK | BTRFS_BLOCK_GROUP_PROFILE_MASK ) &
6303
- btrfs_chunk_type ( leaf , chunk ) ) {
6305
+ type ) {
6304
6306
btrfs_err (root -> fs_info , "unrecognized chunk type: %llu" ,
6305
6307
~(BTRFS_BLOCK_GROUP_TYPE_MASK |
6306
6308
BTRFS_BLOCK_GROUP_PROFILE_MASK ) &
6307
6309
btrfs_chunk_type (leaf , chunk ));
6308
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
6354
read_lock (& map_tree -> map_tree .lock );
6312
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
6597
u32 array_size ;
6555
6598
u32 len = 0 ;
6556
6599
u32 cur_offset ;
6600
+ u64 type ;
6557
6601
struct btrfs_key key ;
6558
6602
6559
6603
ASSERT (BTRFS_SUPER_INFO_SIZE <= root -> nodesize );
@@ -6620,6 +6664,15 @@ int btrfs_read_sys_array(struct btrfs_root *root)
6620
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
6676
len = btrfs_chunk_item_size (num_stripes );
6624
6677
if (cur_offset + len > array_size )
6625
6678
goto out_short_read ;
@@ -6638,12 +6691,14 @@ int btrfs_read_sys_array(struct btrfs_root *root)
6638
6691
sb_array_offset += len ;
6639
6692
cur_offset += len ;
6640
6693
}
6694
+ clear_extent_buffer_uptodate (sb );
6641
6695
free_extent_buffer_stale (sb );
6642
6696
return ret ;
6643
6697
6644
6698
out_short_read :
6645
6699
printk (KERN_ERR "BTRFS: sys_array too short to read %u bytes at offset %u\n" ,
6646
6700
len , cur_offset );
6701
+ clear_extent_buffer_uptodate (sb );
6647
6702
free_extent_buffer_stale (sb );
6648
6703
return - EIO ;
6649
6704
}
@@ -6656,6 +6711,7 @@ int btrfs_read_chunk_tree(struct btrfs_root *root)
6656
6711
struct btrfs_key found_key ;
6657
6712
int ret ;
6658
6713
int slot ;
6714
+ u64 total_dev = 0 ;
6659
6715
6660
6716
root = root -> fs_info -> chunk_root ;
6661
6717
@@ -6697,6 +6753,7 @@ int btrfs_read_chunk_tree(struct btrfs_root *root)
6697
6753
ret = read_one_dev (root , leaf , dev_item );
6698
6754
if (ret )
6699
6755
goto error ;
6756
+ total_dev ++ ;
6700
6757
} else if (found_key .type == BTRFS_CHUNK_ITEM_KEY ) {
6701
6758
struct btrfs_chunk * chunk ;
6702
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
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
6788
ret = 0 ;
6710
6789
error :
6711
6790
unlock_chunks (root );
0 commit comments