diff options
Diffstat (limited to 'fs/btrfs/tree-checker.c')
-rw-r--r-- | fs/btrfs/tree-checker.c | 97 |
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 | */ | ||
457 | int 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 | */ |
454 | static int check_leaf_item(struct btrfs_fs_info *fs_info, | 551 | static int check_leaf_item(struct btrfs_fs_info *fs_info, |