summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/btrfs/ctree.h1
-rw-r--r--fs/btrfs/extent-tree.c2
-rw-r--r--fs/btrfs/tree-checker.c48
3 files changed, 50 insertions, 1 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index b161224b5a0b..20793742c9d3 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -2447,6 +2447,7 @@ enum btrfs_inline_ref_type {
2447int btrfs_get_extent_inline_ref_type(const struct extent_buffer *eb, 2447int btrfs_get_extent_inline_ref_type(const struct extent_buffer *eb,
2448 struct btrfs_extent_inline_ref *iref, 2448 struct btrfs_extent_inline_ref *iref,
2449 enum btrfs_inline_ref_type is_data); 2449 enum btrfs_inline_ref_type is_data);
2450u64 hash_extent_data_ref(u64 root_objectid, u64 owner, u64 offset);
2450 2451
2451u64 btrfs_csum_bytes_to_leaves(struct btrfs_fs_info *fs_info, u64 csum_bytes); 2452u64 btrfs_csum_bytes_to_leaves(struct btrfs_fs_info *fs_info, u64 csum_bytes);
2452 2453
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index cd210550a349..5e8c6a0bac4b 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -438,7 +438,7 @@ int btrfs_get_extent_inline_ref_type(const struct extent_buffer *eb,
438 return BTRFS_REF_TYPE_INVALID; 438 return BTRFS_REF_TYPE_INVALID;
439} 439}
440 440
441static u64 hash_extent_data_ref(u64 root_objectid, u64 owner, u64 offset) 441u64 hash_extent_data_ref(u64 root_objectid, u64 owner, u64 offset)
442{ 442{
443 u32 high_crc = ~(u32)0; 443 u32 high_crc = ~(u32)0;
444 u32 low_crc = ~(u32)0; 444 u32 low_crc = ~(u32)0;
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
1190static 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}