summaryrefslogtreecommitdiffstats
path: root/fs/btrfs/tree-checker.c
diff options
context:
space:
mode:
authorQu Wenruo <wqu@suse.com>2019-08-08 21:24:22 -0400
committerDavid Sterba <dsterba@suse.com>2019-09-09 08:59:12 -0400
commitf82d1c7ca8ae1bf89e8d78c5ecb56b6b228c1a75 (patch)
tree5ed618e1c776ae7cf773a335475cbf8af44c2bdb /fs/btrfs/tree-checker.c
parentf11369897ed4f8609cdee00d3af47c18fe6bda29 (diff)
btrfs: tree-checker: Add EXTENT_ITEM and METADATA_ITEM check
This patch introduces the ability to check extent items. This check involves: - key->objectid check Basic alignment check. - key->type check Against btrfs_extent_item::type and SKINNY_METADATA feature. - key->offset alignment check for EXTENT_ITEM - key->offset check for METADATA_ITEM - item size check Both against minimal size and stepping check. - btrfs_extent_item check Checks its flags and generation. - btrfs_extent_inline_ref checks Against 4 types inline ref. Checks bytenr alignment and tree level. - btrfs_extent_item::refs check Check against total refs found in inline refs. This check would be the most complex single item check due to its nature of inlined items. Signed-off-by: Qu Wenruo <wqu@suse.com> Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
Diffstat (limited to 'fs/btrfs/tree-checker.c')
-rw-r--r--fs/btrfs/tree-checker.c248
1 files changed, 248 insertions, 0 deletions
diff --git a/fs/btrfs/tree-checker.c b/fs/btrfs/tree-checker.c
index d83adda6c090..7eee0bbd8c37 100644
--- a/fs/btrfs/tree-checker.c
+++ b/fs/btrfs/tree-checker.c
@@ -910,6 +910,250 @@ static int check_root_item(struct extent_buffer *leaf, struct btrfs_key *key,
910 return 0; 910 return 0;
911} 911}
912 912
913__printf(3,4)
914__cold
915static void extent_err(const struct extent_buffer *eb, int slot,
916 const char *fmt, ...)
917{
918 struct btrfs_key key;
919 struct va_format vaf;
920 va_list args;
921 u64 bytenr;
922 u64 len;
923
924 btrfs_item_key_to_cpu(eb, &key, slot);
925 bytenr = key.objectid;
926 if (key.type == BTRFS_METADATA_ITEM_KEY)
927 len = eb->fs_info->nodesize;
928 else
929 len = key.offset;
930 va_start(args, fmt);
931
932 vaf.fmt = fmt;
933 vaf.va = &args;
934
935 btrfs_crit(eb->fs_info,
936 "corrupt %s: block=%llu slot=%d extent bytenr=%llu len=%llu %pV",
937 btrfs_header_level(eb) == 0 ? "leaf" : "node",
938 eb->start, slot, bytenr, len, &vaf);
939 va_end(args);
940}
941
942static int check_extent_item(struct extent_buffer *leaf,
943 struct btrfs_key *key, int slot)
944{
945 struct btrfs_fs_info *fs_info = leaf->fs_info;
946 struct btrfs_extent_item *ei;
947 bool is_tree_block = false;
948 unsigned long ptr; /* Current pointer inside inline refs */
949 unsigned long end; /* Extent item end */
950 const u32 item_size = btrfs_item_size_nr(leaf, slot);
951 u64 flags;
952 u64 generation;
953 u64 total_refs; /* Total refs in btrfs_extent_item */
954 u64 inline_refs = 0; /* found total inline refs */
955
956 if (key->type == BTRFS_METADATA_ITEM_KEY &&
957 !btrfs_fs_incompat(fs_info, SKINNY_METADATA)) {
958 generic_err(leaf, slot,
959"invalid key type, METADATA_ITEM type invalid when SKINNY_METADATA feature disabled");
960 return -EUCLEAN;
961 }
962 /* key->objectid is the bytenr for both key types */
963 if (!IS_ALIGNED(key->objectid, fs_info->sectorsize)) {
964 generic_err(leaf, slot,
965 "invalid key objectid, have %llu expect to be aligned to %u",
966 key->objectid, fs_info->sectorsize);
967 return -EUCLEAN;
968 }
969
970 /* key->offset is tree level for METADATA_ITEM_KEY */
971 if (key->type == BTRFS_METADATA_ITEM_KEY &&
972 key->offset >= BTRFS_MAX_LEVEL) {
973 extent_err(leaf, slot,
974 "invalid tree level, have %llu expect [0, %u]",
975 key->offset, BTRFS_MAX_LEVEL - 1);
976 return -EUCLEAN;
977 }
978
979 /*
980 * EXTENT/METADATA_ITEM consists of:
981 * 1) One btrfs_extent_item
982 * Records the total refs, type and generation of the extent.
983 *
984 * 2) One btrfs_tree_block_info (for EXTENT_ITEM and tree backref only)
985 * Records the first key and level of the tree block.
986 *
987 * 2) Zero or more btrfs_extent_inline_ref(s)
988 * Each inline ref has one btrfs_extent_inline_ref shows:
989 * 2.1) The ref type, one of the 4
990 * TREE_BLOCK_REF Tree block only
991 * SHARED_BLOCK_REF Tree block only
992 * EXTENT_DATA_REF Data only
993 * SHARED_DATA_REF Data only
994 * 2.2) Ref type specific data
995 * Either using btrfs_extent_inline_ref::offset, or specific
996 * data structure.
997 */
998 if (item_size < sizeof(*ei)) {
999 extent_err(leaf, slot,
1000 "invalid item size, have %u expect [%zu, %u)",
1001 item_size, sizeof(*ei),
1002 BTRFS_LEAF_DATA_SIZE(fs_info));
1003 return -EUCLEAN;
1004 }
1005 end = item_size + btrfs_item_ptr_offset(leaf, slot);
1006
1007 /* Checks against extent_item */
1008 ei = btrfs_item_ptr(leaf, slot, struct btrfs_extent_item);
1009 flags = btrfs_extent_flags(leaf, ei);
1010 total_refs = btrfs_extent_refs(leaf, ei);
1011 generation = btrfs_extent_generation(leaf, ei);
1012 if (generation > btrfs_super_generation(fs_info->super_copy) + 1) {
1013 extent_err(leaf, slot,
1014 "invalid generation, have %llu expect (0, %llu]",
1015 generation,
1016 btrfs_super_generation(fs_info->super_copy) + 1);
1017 return -EUCLEAN;
1018 }
1019 if (!is_power_of_2(flags & (BTRFS_EXTENT_FLAG_DATA |
1020 BTRFS_EXTENT_FLAG_TREE_BLOCK))) {
1021 extent_err(leaf, slot,
1022 "invalid extent flag, have 0x%llx expect 1 bit set in 0x%llx",
1023 flags, BTRFS_EXTENT_FLAG_DATA |
1024 BTRFS_EXTENT_FLAG_TREE_BLOCK);
1025 return -EUCLEAN;
1026 }
1027 is_tree_block = !!(flags & BTRFS_EXTENT_FLAG_TREE_BLOCK);
1028 if (is_tree_block) {
1029 if (key->type == BTRFS_EXTENT_ITEM_KEY &&
1030 key->offset != fs_info->nodesize) {
1031 extent_err(leaf, slot,
1032 "invalid extent length, have %llu expect %u",
1033 key->offset, fs_info->nodesize);
1034 return -EUCLEAN;
1035 }
1036 } else {
1037 if (key->type != BTRFS_EXTENT_ITEM_KEY) {
1038 extent_err(leaf, slot,
1039 "invalid key type, have %u expect %u for data backref",
1040 key->type, BTRFS_EXTENT_ITEM_KEY);
1041 return -EUCLEAN;
1042 }
1043 if (!IS_ALIGNED(key->offset, fs_info->sectorsize)) {
1044 extent_err(leaf, slot,
1045 "invalid extent length, have %llu expect aligned to %u",
1046 key->offset, fs_info->sectorsize);
1047 return -EUCLEAN;
1048 }
1049 }
1050 ptr = (unsigned long)(struct btrfs_extent_item *)(ei + 1);
1051
1052 /* Check the special case of btrfs_tree_block_info */
1053 if (is_tree_block && key->type != BTRFS_METADATA_ITEM_KEY) {
1054 struct btrfs_tree_block_info *info;
1055
1056 info = (struct btrfs_tree_block_info *)ptr;
1057 if (btrfs_tree_block_level(leaf, info) >= BTRFS_MAX_LEVEL) {
1058 extent_err(leaf, slot,
1059 "invalid tree block info level, have %u expect [0, %u]",
1060 btrfs_tree_block_level(leaf, info),
1061 BTRFS_MAX_LEVEL - 1);
1062 return -EUCLEAN;
1063 }
1064 ptr = (unsigned long)(struct btrfs_tree_block_info *)(info + 1);
1065 }
1066
1067 /* Check inline refs */
1068 while (ptr < end) {
1069 struct btrfs_extent_inline_ref *iref;
1070 struct btrfs_extent_data_ref *dref;
1071 struct btrfs_shared_data_ref *sref;
1072 u64 dref_offset;
1073 u64 inline_offset;
1074 u8 inline_type;
1075
1076 if (ptr + sizeof(*iref) > end) {
1077 extent_err(leaf, slot,
1078"inline ref item overflows extent item, ptr %lu iref size %zu end %lu",
1079 ptr, sizeof(*iref), end);
1080 return -EUCLEAN;
1081 }
1082 iref = (struct btrfs_extent_inline_ref *)ptr;
1083 inline_type = btrfs_extent_inline_ref_type(leaf, iref);
1084 inline_offset = btrfs_extent_inline_ref_offset(leaf, iref);
1085 if (ptr + btrfs_extent_inline_ref_size(inline_type) > end) {
1086 extent_err(leaf, slot,
1087"inline ref item overflows extent item, ptr %lu iref size %u end %lu",
1088 ptr, inline_type, end);
1089 return -EUCLEAN;
1090 }
1091
1092 switch (inline_type) {
1093 /* inline_offset is subvolid of the owner, no need to check */
1094 case BTRFS_TREE_BLOCK_REF_KEY:
1095 inline_refs++;
1096 break;
1097 /* Contains parent bytenr */
1098 case BTRFS_SHARED_BLOCK_REF_KEY:
1099 if (!IS_ALIGNED(inline_offset, fs_info->sectorsize)) {
1100 extent_err(leaf, slot,
1101 "invalid tree parent bytenr, have %llu expect aligned to %u",
1102 inline_offset, fs_info->sectorsize);
1103 return -EUCLEAN;
1104 }
1105 inline_refs++;
1106 break;
1107 /*
1108 * Contains owner subvolid, owner key objectid, adjusted offset.
1109 * The only obvious corruption can happen in that offset.
1110 */
1111 case BTRFS_EXTENT_DATA_REF_KEY:
1112 dref = (struct btrfs_extent_data_ref *)(&iref->offset);
1113 dref_offset = btrfs_extent_data_ref_offset(leaf, dref);
1114 if (!IS_ALIGNED(dref_offset, fs_info->sectorsize)) {
1115 extent_err(leaf, slot,
1116 "invalid data ref offset, have %llu expect aligned to %u",
1117 dref_offset, fs_info->sectorsize);
1118 return -EUCLEAN;
1119 }
1120 inline_refs += btrfs_extent_data_ref_count(leaf, dref);
1121 break;
1122 /* Contains parent bytenr and ref count */
1123 case BTRFS_SHARED_DATA_REF_KEY:
1124 sref = (struct btrfs_shared_data_ref *)(iref + 1);
1125 if (!IS_ALIGNED(inline_offset, fs_info->sectorsize)) {
1126 extent_err(leaf, slot,
1127 "invalid data parent bytenr, have %llu expect aligned to %u",
1128 inline_offset, fs_info->sectorsize);
1129 return -EUCLEAN;
1130 }
1131 inline_refs += btrfs_shared_data_ref_count(leaf, sref);
1132 break;
1133 default:
1134 extent_err(leaf, slot, "unknown inline ref type: %u",
1135 inline_type);
1136 return -EUCLEAN;
1137 }
1138 ptr += btrfs_extent_inline_ref_size(inline_type);
1139 }
1140 /* No padding is allowed */
1141 if (ptr != end) {
1142 extent_err(leaf, slot,
1143 "invalid extent item size, padding bytes found");
1144 return -EUCLEAN;
1145 }
1146
1147 /* Finally, check the inline refs against total refs */
1148 if (inline_refs > total_refs) {
1149 extent_err(leaf, slot,
1150 "invalid extent refs, have %llu expect >= inline %llu",
1151 total_refs, inline_refs);
1152 return -EUCLEAN;
1153 }
1154 return 0;
1155}
1156
913/* 1157/*
914 * Common point to switch the item-specific validation. 1158 * Common point to switch the item-specific validation.
915 */ 1159 */
@@ -948,6 +1192,10 @@ static int check_leaf_item(struct extent_buffer *leaf,
948 case BTRFS_ROOT_ITEM_KEY: 1192 case BTRFS_ROOT_ITEM_KEY:
949 ret = check_root_item(leaf, key, slot); 1193 ret = check_root_item(leaf, key, slot);
950 break; 1194 break;
1195 case BTRFS_EXTENT_ITEM_KEY:
1196 case BTRFS_METADATA_ITEM_KEY:
1197 ret = check_extent_item(leaf, key, slot);
1198 break;
951 } 1199 }
952 return ret; 1200 return ret;
953} 1201}