diff options
author | Qu Wenruo <wqu@suse.com> | 2019-07-16 05:00:34 -0400 |
---|---|---|
committer | David Sterba <dsterba@suse.com> | 2019-09-09 08:59:01 -0400 |
commit | 259ee7754b6793af8bdd77f9ca818bc41cfe9541 (patch) | |
tree | 1df9c3d63c8245a1577e546e6c789faf1baba30d | |
parent | 2a28468e525f3924efed7f29f2bc5a2926e7e19a (diff) |
btrfs: tree-checker: Add ROOT_ITEM check
This patch will introduce ROOT_ITEM check, which includes:
- Key->objectid and key->offset check
Currently only some easy check, e.g. 0 as rootid is invalid.
- Item size check
Root item size is fixed.
- Generation checks
Generation, generation_v2 and last_snapshot should not be greater than
super generation + 1
- Level and alignment check
Level should be in [0, 7], and bytenr must be aligned to sector size.
- Flags check
Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=203261
Reported-by: Jungyeon Yoon <jungyeon.yoon@gmail.com>
Signed-off-by: Qu Wenruo <wqu@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
-rw-r--r-- | fs/btrfs/tree-checker.c | 92 |
1 files changed, 92 insertions, 0 deletions
diff --git a/fs/btrfs/tree-checker.c b/fs/btrfs/tree-checker.c index ccd5706199d7..d83adda6c090 100644 --- a/fs/btrfs/tree-checker.c +++ b/fs/btrfs/tree-checker.c | |||
@@ -821,6 +821,95 @@ static int check_inode_item(struct extent_buffer *leaf, | |||
821 | return 0; | 821 | return 0; |
822 | } | 822 | } |
823 | 823 | ||
824 | static int check_root_item(struct extent_buffer *leaf, struct btrfs_key *key, | ||
825 | int slot) | ||
826 | { | ||
827 | struct btrfs_fs_info *fs_info = leaf->fs_info; | ||
828 | struct btrfs_root_item ri; | ||
829 | const u64 valid_root_flags = BTRFS_ROOT_SUBVOL_RDONLY | | ||
830 | BTRFS_ROOT_SUBVOL_DEAD; | ||
831 | |||
832 | /* No such tree id */ | ||
833 | if (key->objectid == 0) { | ||
834 | generic_err(leaf, slot, "invalid root id 0"); | ||
835 | return -EUCLEAN; | ||
836 | } | ||
837 | |||
838 | /* | ||
839 | * Some older kernel may create ROOT_ITEM with non-zero offset, so here | ||
840 | * we only check offset for reloc tree whose key->offset must be a | ||
841 | * valid tree. | ||
842 | */ | ||
843 | if (key->objectid == BTRFS_TREE_RELOC_OBJECTID && key->offset == 0) { | ||
844 | generic_err(leaf, slot, "invalid root id 0 for reloc tree"); | ||
845 | return -EUCLEAN; | ||
846 | } | ||
847 | |||
848 | if (btrfs_item_size_nr(leaf, slot) != sizeof(ri)) { | ||
849 | generic_err(leaf, slot, | ||
850 | "invalid root item size, have %u expect %zu", | ||
851 | btrfs_item_size_nr(leaf, slot), sizeof(ri)); | ||
852 | } | ||
853 | |||
854 | read_extent_buffer(leaf, &ri, btrfs_item_ptr_offset(leaf, slot), | ||
855 | sizeof(ri)); | ||
856 | |||
857 | /* Generation related */ | ||
858 | if (btrfs_root_generation(&ri) > | ||
859 | btrfs_super_generation(fs_info->super_copy) + 1) { | ||
860 | generic_err(leaf, slot, | ||
861 | "invalid root generation, have %llu expect (0, %llu]", | ||
862 | btrfs_root_generation(&ri), | ||
863 | btrfs_super_generation(fs_info->super_copy) + 1); | ||
864 | return -EUCLEAN; | ||
865 | } | ||
866 | if (btrfs_root_generation_v2(&ri) > | ||
867 | btrfs_super_generation(fs_info->super_copy) + 1) { | ||
868 | generic_err(leaf, slot, | ||
869 | "invalid root v2 generation, have %llu expect (0, %llu]", | ||
870 | btrfs_root_generation_v2(&ri), | ||
871 | btrfs_super_generation(fs_info->super_copy) + 1); | ||
872 | return -EUCLEAN; | ||
873 | } | ||
874 | if (btrfs_root_last_snapshot(&ri) > | ||
875 | btrfs_super_generation(fs_info->super_copy) + 1) { | ||
876 | generic_err(leaf, slot, | ||
877 | "invalid root last_snapshot, have %llu expect (0, %llu]", | ||
878 | btrfs_root_last_snapshot(&ri), | ||
879 | btrfs_super_generation(fs_info->super_copy) + 1); | ||
880 | return -EUCLEAN; | ||
881 | } | ||
882 | |||
883 | /* Alignment and level check */ | ||
884 | if (!IS_ALIGNED(btrfs_root_bytenr(&ri), fs_info->sectorsize)) { | ||
885 | generic_err(leaf, slot, | ||
886 | "invalid root bytenr, have %llu expect to be aligned to %u", | ||
887 | btrfs_root_bytenr(&ri), fs_info->sectorsize); | ||
888 | return -EUCLEAN; | ||
889 | } | ||
890 | if (btrfs_root_level(&ri) >= BTRFS_MAX_LEVEL) { | ||
891 | generic_err(leaf, slot, | ||
892 | "invalid root level, have %u expect [0, %u]", | ||
893 | btrfs_root_level(&ri), BTRFS_MAX_LEVEL - 1); | ||
894 | return -EUCLEAN; | ||
895 | } | ||
896 | if (ri.drop_level >= BTRFS_MAX_LEVEL) { | ||
897 | generic_err(leaf, slot, | ||
898 | "invalid root level, have %u expect [0, %u]", | ||
899 | ri.drop_level, BTRFS_MAX_LEVEL - 1); | ||
900 | return -EUCLEAN; | ||
901 | } | ||
902 | |||
903 | /* Flags check */ | ||
904 | if (btrfs_root_flags(&ri) & ~valid_root_flags) { | ||
905 | generic_err(leaf, slot, | ||
906 | "invalid root flags, have 0x%llx expect mask 0x%llx", | ||
907 | btrfs_root_flags(&ri), valid_root_flags); | ||
908 | return -EUCLEAN; | ||
909 | } | ||
910 | return 0; | ||
911 | } | ||
912 | |||
824 | /* | 913 | /* |
825 | * Common point to switch the item-specific validation. | 914 | * Common point to switch the item-specific validation. |
826 | */ | 915 | */ |
@@ -856,6 +945,9 @@ static int check_leaf_item(struct extent_buffer *leaf, | |||
856 | case BTRFS_INODE_ITEM_KEY: | 945 | case BTRFS_INODE_ITEM_KEY: |
857 | ret = check_inode_item(leaf, key, slot); | 946 | ret = check_inode_item(leaf, key, slot); |
858 | break; | 947 | break; |
948 | case BTRFS_ROOT_ITEM_KEY: | ||
949 | ret = check_root_item(leaf, key, slot); | ||
950 | break; | ||
859 | } | 951 | } |
860 | return ret; | 952 | return ret; |
861 | } | 953 | } |