Skip to content

Commit 0785a9a

Browse files
adam900710kdave
authored andcommitted
btrfs: tree-checker: Add EXTENT_DATA_REF check
EXTENT_DATA_REF is a little like DIR_ITEM which contains hash in its key->offset. This patch will check the following contents: - Key->objectid Basic alignment check. - Hash Hash of each extent_data_ref item must match key->offset. - Offset Basic alignment check. Signed-off-by: Qu Wenruo <[email protected]> Reviewed-by: David Sterba <[email protected]> Signed-off-by: David Sterba <[email protected]>
1 parent e2406a6 commit 0785a9a

File tree

3 files changed

+50
-1
lines changed

3 files changed

+50
-1
lines changed

fs/btrfs/ctree.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2447,6 +2447,7 @@ enum btrfs_inline_ref_type {
24472447
int btrfs_get_extent_inline_ref_type(const struct extent_buffer *eb,
24482448
struct btrfs_extent_inline_ref *iref,
24492449
enum btrfs_inline_ref_type is_data);
2450+
u64 hash_extent_data_ref(u64 root_objectid, u64 owner, u64 offset);
24502451

24512452
u64 btrfs_csum_bytes_to_leaves(struct btrfs_fs_info *fs_info, u64 csum_bytes);
24522453

fs/btrfs/extent-tree.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -438,7 +438,7 @@ int btrfs_get_extent_inline_ref_type(const struct extent_buffer *eb,
438438
return BTRFS_REF_TYPE_INVALID;
439439
}
440440

441-
static u64 hash_extent_data_ref(u64 root_objectid, u64 owner, u64 offset)
441+
u64 hash_extent_data_ref(u64 root_objectid, u64 owner, u64 offset)
442442
{
443443
u32 high_crc = ~(u32)0;
444444
u32 low_crc = ~(u32)0;

fs/btrfs/tree-checker.c

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1187,6 +1187,51 @@ static int check_simple_keyed_refs(struct extent_buffer *leaf,
11871187
return 0;
11881188
}
11891189

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+
11901235
/*
11911236
* Common point to switch the item-specific validation.
11921237
*/
@@ -1234,6 +1279,9 @@ static int check_leaf_item(struct extent_buffer *leaf,
12341279
case BTRFS_SHARED_BLOCK_REF_KEY:
12351280
ret = check_simple_keyed_refs(leaf, key, slot);
12361281
break;
1282+
case BTRFS_EXTENT_DATA_REF_KEY:
1283+
ret = check_extent_data_ref(leaf, key, slot);
1284+
break;
12371285
}
12381286
return ret;
12391287
}

0 commit comments

Comments
 (0)