diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/btrfs/tree-checker.c | 74 | ||||
-rw-r--r-- | fs/btrfs/volumes.c | 9 | ||||
-rw-r--r-- | fs/btrfs/volumes.h | 9 |
3 files changed, 83 insertions, 9 deletions
diff --git a/fs/btrfs/tree-checker.c b/fs/btrfs/tree-checker.c index 33d04fc4d280..00ab4e783b9f 100644 --- a/fs/btrfs/tree-checker.c +++ b/fs/btrfs/tree-checker.c | |||
@@ -600,6 +600,77 @@ int btrfs_check_chunk_valid(struct btrfs_fs_info *fs_info, | |||
600 | return 0; | 600 | return 0; |
601 | } | 601 | } |
602 | 602 | ||
603 | __printf(4, 5) | ||
604 | __cold | ||
605 | static void dev_item_err(const struct btrfs_fs_info *fs_info, | ||
606 | const struct extent_buffer *eb, int slot, | ||
607 | const char *fmt, ...) | ||
608 | { | ||
609 | struct btrfs_key key; | ||
610 | struct va_format vaf; | ||
611 | va_list args; | ||
612 | |||
613 | btrfs_item_key_to_cpu(eb, &key, slot); | ||
614 | va_start(args, fmt); | ||
615 | |||
616 | vaf.fmt = fmt; | ||
617 | vaf.va = &args; | ||
618 | |||
619 | btrfs_crit(fs_info, | ||
620 | "corrupt %s: root=%llu block=%llu slot=%d devid=%llu %pV", | ||
621 | btrfs_header_level(eb) == 0 ? "leaf" : "node", | ||
622 | btrfs_header_owner(eb), btrfs_header_bytenr(eb), slot, | ||
623 | key.objectid, &vaf); | ||
624 | va_end(args); | ||
625 | } | ||
626 | |||
627 | static int check_dev_item(struct btrfs_fs_info *fs_info, | ||
628 | struct extent_buffer *leaf, | ||
629 | struct btrfs_key *key, int slot) | ||
630 | { | ||
631 | struct btrfs_dev_item *ditem; | ||
632 | u64 max_devid = max(BTRFS_MAX_DEVS(fs_info), BTRFS_MAX_DEVS_SYS_CHUNK); | ||
633 | |||
634 | if (key->objectid != BTRFS_DEV_ITEMS_OBJECTID) { | ||
635 | dev_item_err(fs_info, leaf, slot, | ||
636 | "invalid objectid: has=%llu expect=%llu", | ||
637 | key->objectid, BTRFS_DEV_ITEMS_OBJECTID); | ||
638 | return -EUCLEAN; | ||
639 | } | ||
640 | if (key->offset > max_devid) { | ||
641 | dev_item_err(fs_info, leaf, slot, | ||
642 | "invalid devid: has=%llu expect=[0, %llu]", | ||
643 | key->offset, max_devid); | ||
644 | return -EUCLEAN; | ||
645 | } | ||
646 | ditem = btrfs_item_ptr(leaf, slot, struct btrfs_dev_item); | ||
647 | if (btrfs_device_id(leaf, ditem) != key->offset) { | ||
648 | dev_item_err(fs_info, leaf, slot, | ||
649 | "devid mismatch: key has=%llu item has=%llu", | ||
650 | key->offset, btrfs_device_id(leaf, ditem)); | ||
651 | return -EUCLEAN; | ||
652 | } | ||
653 | |||
654 | /* | ||
655 | * For device total_bytes, we don't have reliable way to check it, as | ||
656 | * it can be 0 for device removal. Device size check can only be done | ||
657 | * by dev extents check. | ||
658 | */ | ||
659 | if (btrfs_device_bytes_used(leaf, ditem) > | ||
660 | btrfs_device_total_bytes(leaf, ditem)) { | ||
661 | dev_item_err(fs_info, leaf, slot, | ||
662 | "invalid bytes used: have %llu expect [0, %llu]", | ||
663 | btrfs_device_bytes_used(leaf, ditem), | ||
664 | btrfs_device_total_bytes(leaf, ditem)); | ||
665 | return -EUCLEAN; | ||
666 | } | ||
667 | /* | ||
668 | * Remaining members like io_align/type/gen/dev_group aren't really | ||
669 | * utilized. Skip them to make later usage of them easier. | ||
670 | */ | ||
671 | return 0; | ||
672 | } | ||
673 | |||
603 | /* | 674 | /* |
604 | * Common point to switch the item-specific validation. | 675 | * Common point to switch the item-specific validation. |
605 | */ | 676 | */ |
@@ -630,6 +701,9 @@ static int check_leaf_item(struct btrfs_fs_info *fs_info, | |||
630 | ret = btrfs_check_chunk_valid(fs_info, leaf, chunk, | 701 | ret = btrfs_check_chunk_valid(fs_info, leaf, chunk, |
631 | key->offset); | 702 | key->offset); |
632 | break; | 703 | break; |
704 | case BTRFS_DEV_ITEM_KEY: | ||
705 | ret = check_dev_item(fs_info, leaf, key, slot); | ||
706 | break; | ||
633 | } | 707 | } |
634 | return ret; | 708 | return ret; |
635 | } | 709 | } |
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 97dbd7f37674..77bca3a61e26 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c | |||
@@ -4958,15 +4958,6 @@ static void check_raid56_incompat_flag(struct btrfs_fs_info *info, u64 type) | |||
4958 | btrfs_set_fs_incompat(info, RAID56); | 4958 | btrfs_set_fs_incompat(info, RAID56); |
4959 | } | 4959 | } |
4960 | 4960 | ||
4961 | #define BTRFS_MAX_DEVS(info) ((BTRFS_MAX_ITEM_SIZE(info) \ | ||
4962 | - sizeof(struct btrfs_chunk)) \ | ||
4963 | / sizeof(struct btrfs_stripe) + 1) | ||
4964 | |||
4965 | #define BTRFS_MAX_DEVS_SYS_CHUNK ((BTRFS_SYSTEM_CHUNK_ARRAY_SIZE \ | ||
4966 | - 2 * sizeof(struct btrfs_disk_key) \ | ||
4967 | - 2 * sizeof(struct btrfs_chunk)) \ | ||
4968 | / sizeof(struct btrfs_stripe) + 1) | ||
4969 | |||
4970 | static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans, | 4961 | static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans, |
4971 | u64 start, u64 type) | 4962 | u64 start, u64 type) |
4972 | { | 4963 | { |
diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h index 3ad9d58d1b66..38ed94b77202 100644 --- a/fs/btrfs/volumes.h +++ b/fs/btrfs/volumes.h | |||
@@ -258,6 +258,15 @@ struct btrfs_fs_devices { | |||
258 | 258 | ||
259 | #define BTRFS_BIO_INLINE_CSUM_SIZE 64 | 259 | #define BTRFS_BIO_INLINE_CSUM_SIZE 64 |
260 | 260 | ||
261 | #define BTRFS_MAX_DEVS(info) ((BTRFS_MAX_ITEM_SIZE(info) \ | ||
262 | - sizeof(struct btrfs_chunk)) \ | ||
263 | / sizeof(struct btrfs_stripe) + 1) | ||
264 | |||
265 | #define BTRFS_MAX_DEVS_SYS_CHUNK ((BTRFS_SYSTEM_CHUNK_ARRAY_SIZE \ | ||
266 | - 2 * sizeof(struct btrfs_disk_key) \ | ||
267 | - 2 * sizeof(struct btrfs_chunk)) \ | ||
268 | / sizeof(struct btrfs_stripe) + 1) | ||
269 | |||
261 | /* | 270 | /* |
262 | * we need the mirror number and stripe index to be passed around | 271 | * we need the mirror number and stripe index to be passed around |
263 | * the call chain while we are processing end_io (especially errors). | 272 | * the call chain while we are processing end_io (especially errors). |