diff options
Diffstat (limited to 'fs/btrfs/tree-checker.c')
-rw-r--r-- | fs/btrfs/tree-checker.c | 48 |
1 files changed, 48 insertions, 0 deletions
diff --git a/fs/btrfs/tree-checker.c b/fs/btrfs/tree-checker.c index 0a56616bef9a..9645389a1187 100644 --- a/fs/btrfs/tree-checker.c +++ b/fs/btrfs/tree-checker.c | |||
@@ -1187,6 +1187,51 @@ static int check_simple_keyed_refs(struct extent_buffer *leaf, | |||
1187 | return 0; | 1187 | return 0; |
1188 | } | 1188 | } |
1189 | 1189 | ||
1190 | static int check_extent_data_ref(struct extent_buffer *leaf, | ||
1191 | struct btrfs_key *key, int slot) | ||
1192 | { | ||
1193 | struct btrfs_extent_data_ref *dref; | ||
1194 | unsigned long ptr = btrfs_item_ptr_offset(leaf, slot); | ||
1195 | const unsigned long end = ptr + btrfs_item_size_nr(leaf, slot); | ||
1196 | |||
1197 | if (btrfs_item_size_nr(leaf, slot) % sizeof(*dref) != 0) { | ||
1198 | generic_err(leaf, slot, | ||
1199 | "invalid item size, have %u expect aligned to %zu for key type %u", | ||
1200 | btrfs_item_size_nr(leaf, slot), | ||
1201 | sizeof(*dref), key->type); | ||
1202 | } | ||
1203 | if (!IS_ALIGNED(key->objectid, leaf->fs_info->sectorsize)) { | ||
1204 | generic_err(leaf, slot, | ||
1205 | "invalid key objectid for shared block ref, have %llu expect aligned to %u", | ||
1206 | key->objectid, leaf->fs_info->sectorsize); | ||
1207 | return -EUCLEAN; | ||
1208 | } | ||
1209 | for (; ptr < end; ptr += sizeof(*dref)) { | ||
1210 | u64 root_objectid; | ||
1211 | u64 owner; | ||
1212 | u64 offset; | ||
1213 | u64 hash; | ||
1214 | |||
1215 | dref = (struct btrfs_extent_data_ref *)ptr; | ||
1216 | root_objectid = btrfs_extent_data_ref_root(leaf, dref); | ||
1217 | owner = btrfs_extent_data_ref_objectid(leaf, dref); | ||
1218 | offset = btrfs_extent_data_ref_offset(leaf, dref); | ||
1219 | hash = hash_extent_data_ref(root_objectid, owner, offset); | ||
1220 | if (hash != key->offset) { | ||
1221 | extent_err(leaf, slot, | ||
1222 | "invalid extent data ref hash, item has 0x%016llx key has 0x%016llx", | ||
1223 | hash, key->offset); | ||
1224 | return -EUCLEAN; | ||
1225 | } | ||
1226 | if (!IS_ALIGNED(offset, leaf->fs_info->sectorsize)) { | ||
1227 | extent_err(leaf, slot, | ||
1228 | "invalid extent data backref offset, have %llu expect aligned to %u", | ||
1229 | offset, leaf->fs_info->sectorsize); | ||
1230 | } | ||
1231 | } | ||
1232 | return 0; | ||
1233 | } | ||
1234 | |||
1190 | /* | 1235 | /* |
1191 | * Common point to switch the item-specific validation. | 1236 | * Common point to switch the item-specific validation. |
1192 | */ | 1237 | */ |
@@ -1234,6 +1279,9 @@ static int check_leaf_item(struct extent_buffer *leaf, | |||
1234 | case BTRFS_SHARED_BLOCK_REF_KEY: | 1279 | case BTRFS_SHARED_BLOCK_REF_KEY: |
1235 | ret = check_simple_keyed_refs(leaf, key, slot); | 1280 | ret = check_simple_keyed_refs(leaf, key, slot); |
1236 | break; | 1281 | break; |
1282 | case BTRFS_EXTENT_DATA_REF_KEY: | ||
1283 | ret = check_extent_data_ref(leaf, key, slot); | ||
1284 | break; | ||
1237 | } | 1285 | } |
1238 | return ret; | 1286 | return ret; |
1239 | } | 1287 | } |