summaryrefslogtreecommitdiffstats
path: root/fs/btrfs/tree-checker.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/btrfs/tree-checker.c')
-rw-r--r--fs/btrfs/tree-checker.c97
1 files changed, 97 insertions, 0 deletions
diff --git a/fs/btrfs/tree-checker.c b/fs/btrfs/tree-checker.c
index a62e1e837a89..eee861975816 100644
--- a/fs/btrfs/tree-checker.c
+++ b/fs/btrfs/tree-checker.c
@@ -449,6 +449,103 @@ static int check_block_group_item(struct btrfs_fs_info *fs_info,
449} 449}
450 450
451/* 451/*
452 * The common chunk check which could also work on super block sys chunk array.
453 *
454 * Return -EIO if anything is corrupted.
455 * Return 0 if everything is OK.
456 */
457int btrfs_check_chunk_valid(struct btrfs_fs_info *fs_info,
458 struct extent_buffer *leaf,
459 struct btrfs_chunk *chunk, u64 logical)
460{
461 u64 length;
462 u64 stripe_len;
463 u16 num_stripes;
464 u16 sub_stripes;
465 u64 type;
466 u64 features;
467 bool mixed = false;
468
469 length = btrfs_chunk_length(leaf, chunk);
470 stripe_len = btrfs_chunk_stripe_len(leaf, chunk);
471 num_stripes = btrfs_chunk_num_stripes(leaf, chunk);
472 sub_stripes = btrfs_chunk_sub_stripes(leaf, chunk);
473 type = btrfs_chunk_type(leaf, chunk);
474
475 if (!num_stripes) {
476 btrfs_err(fs_info, "invalid chunk num_stripes: %u",
477 num_stripes);
478 return -EIO;
479 }
480 if (!IS_ALIGNED(logical, fs_info->sectorsize)) {
481 btrfs_err(fs_info, "invalid chunk logical %llu", logical);
482 return -EIO;
483 }
484 if (btrfs_chunk_sector_size(leaf, chunk) != fs_info->sectorsize) {
485 btrfs_err(fs_info, "invalid chunk sectorsize %u",
486 btrfs_chunk_sector_size(leaf, chunk));
487 return -EIO;
488 }
489 if (!length || !IS_ALIGNED(length, fs_info->sectorsize)) {
490 btrfs_err(fs_info, "invalid chunk length %llu", length);
491 return -EIO;
492 }
493 if (!is_power_of_2(stripe_len) || stripe_len != BTRFS_STRIPE_LEN) {
494 btrfs_err(fs_info, "invalid chunk stripe length: %llu",
495 stripe_len);
496 return -EIO;
497 }
498 if (~(BTRFS_BLOCK_GROUP_TYPE_MASK | BTRFS_BLOCK_GROUP_PROFILE_MASK) &
499 type) {
500 btrfs_err(fs_info, "unrecognized chunk type: %llu",
501 ~(BTRFS_BLOCK_GROUP_TYPE_MASK |
502 BTRFS_BLOCK_GROUP_PROFILE_MASK) &
503 btrfs_chunk_type(leaf, chunk));
504 return -EIO;
505 }
506
507 if ((type & BTRFS_BLOCK_GROUP_TYPE_MASK) == 0) {
508 btrfs_err(fs_info, "missing chunk type flag: 0x%llx", type);
509 return -EIO;
510 }
511
512 if ((type & BTRFS_BLOCK_GROUP_SYSTEM) &&
513 (type & (BTRFS_BLOCK_GROUP_METADATA | BTRFS_BLOCK_GROUP_DATA))) {
514 btrfs_err(fs_info,
515 "system chunk with data or metadata type: 0x%llx", type);
516 return -EIO;
517 }
518
519 features = btrfs_super_incompat_flags(fs_info->super_copy);
520 if (features & BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS)
521 mixed = true;
522
523 if (!mixed) {
524 if ((type & BTRFS_BLOCK_GROUP_METADATA) &&
525 (type & BTRFS_BLOCK_GROUP_DATA)) {
526 btrfs_err(fs_info,
527 "mixed chunk type in non-mixed mode: 0x%llx", type);
528 return -EIO;
529 }
530 }
531
532 if ((type & BTRFS_BLOCK_GROUP_RAID10 && sub_stripes != 2) ||
533 (type & BTRFS_BLOCK_GROUP_RAID1 && num_stripes != 2) ||
534 (type & BTRFS_BLOCK_GROUP_RAID5 && num_stripes < 2) ||
535 (type & BTRFS_BLOCK_GROUP_RAID6 && num_stripes < 3) ||
536 (type & BTRFS_BLOCK_GROUP_DUP && num_stripes != 2) ||
537 ((type & BTRFS_BLOCK_GROUP_PROFILE_MASK) == 0 && num_stripes != 1)) {
538 btrfs_err(fs_info,
539 "invalid num_stripes:sub_stripes %u:%u for profile %llu",
540 num_stripes, sub_stripes,
541 type & BTRFS_BLOCK_GROUP_PROFILE_MASK);
542 return -EIO;
543 }
544
545 return 0;
546}
547
548/*
452 * Common point to switch the item-specific validation. 549 * Common point to switch the item-specific validation.
453 */ 550 */
454static int check_leaf_item(struct btrfs_fs_info *fs_info, 551static int check_leaf_item(struct btrfs_fs_info *fs_info,