Message ID | 20190807140843.2728-4-wqu@suse.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | btrfs: tree-checker: Add extent items check | expand |
On Wed, Aug 07, 2019 at 10:08:43PM +0800, Qu Wenruo wrote: > 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 <wqu@suse.com> > --- > fs/btrfs/ctree.h | 1 + > fs/btrfs/extent-tree.c | 2 +- > fs/btrfs/tree-checker.c | 48 +++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 50 insertions(+), 1 deletion(-) > > diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h > index 0a61dff27f57..710ea3a6608c 100644 > --- a/fs/btrfs/ctree.h > +++ b/fs/btrfs/ctree.h > @@ -2679,6 +2679,7 @@ enum btrfs_inline_ref_type { > int btrfs_get_extent_inline_ref_type(const struct extent_buffer *eb, > struct btrfs_extent_inline_ref *iref, > enum btrfs_inline_ref_type is_data); > +u64 hash_extent_data_ref(u64 root_objectid, u64 owner, u64 offset); > > u64 btrfs_csum_bytes_to_leaves(struct btrfs_fs_info *fs_info, u64 csum_bytes); > > diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c > index b4e9e36b65f1..c0888ed503df 100644 > --- a/fs/btrfs/extent-tree.c > +++ b/fs/btrfs/extent-tree.c > @@ -1114,7 +1114,7 @@ int btrfs_get_extent_inline_ref_type(const struct extent_buffer *eb, > return BTRFS_REF_TYPE_INVALID; > } > > -static u64 hash_extent_data_ref(u64 root_objectid, u64 owner, u64 offset) > +u64 hash_extent_data_ref(u64 root_objectid, u64 owner, u64 offset) > { > u32 high_crc = ~(u32)0; > u32 low_crc = ~(u32)0; > diff --git a/fs/btrfs/tree-checker.c b/fs/btrfs/tree-checker.c > index 6aaf3650b13d..5755a7a8477f 100644 > --- a/fs/btrfs/tree-checker.c > +++ b/fs/btrfs/tree-checker.c > @@ -1178,6 +1178,51 @@ static int check_simple_keyed_refs(struct extent_buffer *leaf, > return 0; > } > > +static int check_extent_data_ref(struct extent_buffer *leaf, > + struct btrfs_key *key, int slot) > +{ > + struct btrfs_extent_data_ref *dref; > + u64 ptr = btrfs_item_ptr_offset(leaf, slot); > + u64 end = ptr + btrfs_item_size_nr(leaf, slot); same here, unsigned long > + > + if (btrfs_item_size_nr(leaf, slot) % sizeof(*dref) != 0) { > + generic_err(leaf, slot, > + "invalid item size, have %u expect aligned to %lu for key type %u", > + btrfs_item_size_nr(leaf, slot), > + sizeof(*dref), key->type); sizeof needs %zu > + } > + if (!IS_ALIGNED(key->objectid, leaf->fs_info->sectorsize)) { > + generic_err(leaf, slot, > +"invalid key objectid for shared block ref, have %llu expect aligned to %u", > + key->objectid, leaf->fs_info->sectorsize); > + return -EUCLEAN; > + } > + for (; ptr < end; ptr += sizeof(*dref)) { > + u64 root_objectid; > + u64 owner; > + u64 offset; > + u64 hash; > + > + dref = (struct btrfs_extent_data_ref *)ptr; > + root_objectid = btrfs_extent_data_ref_root(leaf, dref); > + owner = btrfs_extent_data_ref_objectid(leaf, dref); > + offset = btrfs_extent_data_ref_offset(leaf, dref); > + hash = hash_extent_data_ref(root_objectid, owner, offset); > + if (hash != key->offset) { > + extent_err(leaf, slot, > + "invalid extent data ref hash, item have 0x%016llx key have 0x%016llx", > + hash, key->offset); > + return -EUCLEAN; > + } > + if (!IS_ALIGNED(offset, leaf->fs_info->sectorsize)) { > + extent_err(leaf, slot, > + "invalid extent data backref offset, have %llu expect aligned to %u", > + offset, leaf->fs_info->sectorsize); > + } > + } > + return 0; > +} > + > /* > * Common point to switch the item-specific validation. > */ > @@ -1225,6 +1270,9 @@ static int check_leaf_item(struct extent_buffer *leaf, > case BTRFS_SHARED_BLOCK_REF_KEY: > ret = check_simple_keyed_refs(leaf, key, slot); > break; > + case BTRFS_EXTENT_DATA_REF_KEY: > + ret = check_extent_data_ref(leaf, key, slot); > + break; > } > return ret; > } > -- > 2.22.0
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 0a61dff27f57..710ea3a6608c 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -2679,6 +2679,7 @@ enum btrfs_inline_ref_type { int btrfs_get_extent_inline_ref_type(const struct extent_buffer *eb, struct btrfs_extent_inline_ref *iref, enum btrfs_inline_ref_type is_data); +u64 hash_extent_data_ref(u64 root_objectid, u64 owner, u64 offset); u64 btrfs_csum_bytes_to_leaves(struct btrfs_fs_info *fs_info, u64 csum_bytes); diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index b4e9e36b65f1..c0888ed503df 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -1114,7 +1114,7 @@ int btrfs_get_extent_inline_ref_type(const struct extent_buffer *eb, return BTRFS_REF_TYPE_INVALID; } -static u64 hash_extent_data_ref(u64 root_objectid, u64 owner, u64 offset) +u64 hash_extent_data_ref(u64 root_objectid, u64 owner, u64 offset) { u32 high_crc = ~(u32)0; u32 low_crc = ~(u32)0; diff --git a/fs/btrfs/tree-checker.c b/fs/btrfs/tree-checker.c index 6aaf3650b13d..5755a7a8477f 100644 --- a/fs/btrfs/tree-checker.c +++ b/fs/btrfs/tree-checker.c @@ -1178,6 +1178,51 @@ static int check_simple_keyed_refs(struct extent_buffer *leaf, return 0; } +static int check_extent_data_ref(struct extent_buffer *leaf, + struct btrfs_key *key, int slot) +{ + struct btrfs_extent_data_ref *dref; + u64 ptr = btrfs_item_ptr_offset(leaf, slot); + u64 end = ptr + btrfs_item_size_nr(leaf, slot); + + if (btrfs_item_size_nr(leaf, slot) % sizeof(*dref) != 0) { + generic_err(leaf, slot, + "invalid item size, have %u expect aligned to %lu for key type %u", + btrfs_item_size_nr(leaf, slot), + sizeof(*dref), key->type); + } + if (!IS_ALIGNED(key->objectid, leaf->fs_info->sectorsize)) { + generic_err(leaf, slot, +"invalid key objectid for shared block ref, have %llu expect aligned to %u", + key->objectid, leaf->fs_info->sectorsize); + return -EUCLEAN; + } + for (; ptr < end; ptr += sizeof(*dref)) { + u64 root_objectid; + u64 owner; + u64 offset; + u64 hash; + + dref = (struct btrfs_extent_data_ref *)ptr; + root_objectid = btrfs_extent_data_ref_root(leaf, dref); + owner = btrfs_extent_data_ref_objectid(leaf, dref); + offset = btrfs_extent_data_ref_offset(leaf, dref); + hash = hash_extent_data_ref(root_objectid, owner, offset); + if (hash != key->offset) { + extent_err(leaf, slot, + "invalid extent data ref hash, item have 0x%016llx key have 0x%016llx", + hash, key->offset); + return -EUCLEAN; + } + if (!IS_ALIGNED(offset, leaf->fs_info->sectorsize)) { + extent_err(leaf, slot, + "invalid extent data backref offset, have %llu expect aligned to %u", + offset, leaf->fs_info->sectorsize); + } + } + return 0; +} + /* * Common point to switch the item-specific validation. */ @@ -1225,6 +1270,9 @@ static int check_leaf_item(struct extent_buffer *leaf, case BTRFS_SHARED_BLOCK_REF_KEY: ret = check_simple_keyed_refs(leaf, key, slot); break; + case BTRFS_EXTENT_DATA_REF_KEY: + ret = check_extent_data_ref(leaf, key, slot); + break; } return ret; }
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 <wqu@suse.com> --- fs/btrfs/ctree.h | 1 + fs/btrfs/extent-tree.c | 2 +- fs/btrfs/tree-checker.c | 48 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 1 deletion(-)