Commit 64ecdb64 authored by Liu Bo's avatar Liu Bo Committed by David Sterba

Btrfs: add one more sanity check for shared ref type

Every shared ref has a parent tree block, which can be get from
btrfs_extent_inline_ref_offset().  And the tree block must be aligned
to the nodesize, so we'd know this inline ref is not valid if this
block's bytenr is not aligned to the nodesize, in which case, most
likely the ref type has been misused.

This adds the above mentioned check and also updates
print_extent_item() called by btrfs_print_leaf() to point out the
invalid ref while printing the tree structure.
Signed-off-by: default avatarLiu Bo <bo.li.liu@oracle.com>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
parent cdccee99
...@@ -1158,19 +1158,40 @@ int btrfs_get_extent_inline_ref_type(const struct extent_buffer *eb, ...@@ -1158,19 +1158,40 @@ int btrfs_get_extent_inline_ref_type(const struct extent_buffer *eb,
enum btrfs_inline_ref_type is_data) enum btrfs_inline_ref_type is_data)
{ {
int type = btrfs_extent_inline_ref_type(eb, iref); int type = btrfs_extent_inline_ref_type(eb, iref);
u64 offset = btrfs_extent_inline_ref_offset(eb, iref);
if (type == BTRFS_TREE_BLOCK_REF_KEY || if (type == BTRFS_TREE_BLOCK_REF_KEY ||
type == BTRFS_SHARED_BLOCK_REF_KEY || type == BTRFS_SHARED_BLOCK_REF_KEY ||
type == BTRFS_SHARED_DATA_REF_KEY || type == BTRFS_SHARED_DATA_REF_KEY ||
type == BTRFS_EXTENT_DATA_REF_KEY) { type == BTRFS_EXTENT_DATA_REF_KEY) {
if (is_data == BTRFS_REF_TYPE_BLOCK) { if (is_data == BTRFS_REF_TYPE_BLOCK) {
if (type == BTRFS_TREE_BLOCK_REF_KEY || if (type == BTRFS_TREE_BLOCK_REF_KEY)
type == BTRFS_SHARED_BLOCK_REF_KEY)
return type; return type;
if (type == BTRFS_SHARED_BLOCK_REF_KEY) {
ASSERT(eb->fs_info);
/*
* Every shared one has parent tree
* block, which must be aligned to
* nodesize.
*/
if (offset &&
IS_ALIGNED(offset, eb->fs_info->nodesize))
return type;
}
} else if (is_data == BTRFS_REF_TYPE_DATA) { } else if (is_data == BTRFS_REF_TYPE_DATA) {
if (type == BTRFS_EXTENT_DATA_REF_KEY || if (type == BTRFS_EXTENT_DATA_REF_KEY)
type == BTRFS_SHARED_DATA_REF_KEY)
return type; return type;
if (type == BTRFS_SHARED_DATA_REF_KEY) {
ASSERT(eb->fs_info);
/*
* Every shared one has parent tree
* block, which must be aligned to
* nodesize.
*/
if (offset &&
IS_ALIGNED(offset, eb->fs_info->nodesize))
return type;
}
} else { } else {
ASSERT(is_data == BTRFS_REF_TYPE_ANY); ASSERT(is_data == BTRFS_REF_TYPE_ANY);
return type; return type;
......
...@@ -44,7 +44,7 @@ static void print_dev_item(struct extent_buffer *eb, ...@@ -44,7 +44,7 @@ static void print_dev_item(struct extent_buffer *eb,
static void print_extent_data_ref(struct extent_buffer *eb, static void print_extent_data_ref(struct extent_buffer *eb,
struct btrfs_extent_data_ref *ref) struct btrfs_extent_data_ref *ref)
{ {
pr_info("\t\textent data backref root %llu objectid %llu offset %llu count %u\n", pr_cont("extent data backref root %llu objectid %llu offset %llu count %u\n",
btrfs_extent_data_ref_root(eb, ref), btrfs_extent_data_ref_root(eb, ref),
btrfs_extent_data_ref_objectid(eb, ref), btrfs_extent_data_ref_objectid(eb, ref),
btrfs_extent_data_ref_offset(eb, ref), btrfs_extent_data_ref_offset(eb, ref),
...@@ -63,6 +63,7 @@ static void print_extent_item(struct extent_buffer *eb, int slot, int type) ...@@ -63,6 +63,7 @@ static void print_extent_item(struct extent_buffer *eb, int slot, int type)
u32 item_size = btrfs_item_size_nr(eb, slot); u32 item_size = btrfs_item_size_nr(eb, slot);
u64 flags; u64 flags;
u64 offset; u64 offset;
int ref_index = 0;
if (item_size < sizeof(*ei)) { if (item_size < sizeof(*ei)) {
#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 #ifdef BTRFS_COMPAT_EXTENT_TREE_V0
...@@ -104,12 +105,20 @@ static void print_extent_item(struct extent_buffer *eb, int slot, int type) ...@@ -104,12 +105,20 @@ static void print_extent_item(struct extent_buffer *eb, int slot, int type)
iref = (struct btrfs_extent_inline_ref *)ptr; iref = (struct btrfs_extent_inline_ref *)ptr;
type = btrfs_extent_inline_ref_type(eb, iref); type = btrfs_extent_inline_ref_type(eb, iref);
offset = btrfs_extent_inline_ref_offset(eb, iref); offset = btrfs_extent_inline_ref_offset(eb, iref);
pr_info("\t\tref#%d: ", ref_index++);
switch (type) { switch (type) {
case BTRFS_TREE_BLOCK_REF_KEY: case BTRFS_TREE_BLOCK_REF_KEY:
pr_info("\t\ttree block backref root %llu\n", offset); pr_cont("tree block backref root %llu\n", offset);
break; break;
case BTRFS_SHARED_BLOCK_REF_KEY: case BTRFS_SHARED_BLOCK_REF_KEY:
pr_info("\t\tshared block backref parent %llu\n", offset); pr_cont("shared block backref parent %llu\n", offset);
/*
* offset is supposed to be a tree block which
* must be aligned to nodesize.
*/
if (!IS_ALIGNED(offset, eb->fs_info->nodesize))
pr_info("\t\t\t(parent %llu is NOT ALIGNED to nodesize %llu)\n",
offset, (unsigned long long)eb->fs_info->nodesize);
break; break;
case BTRFS_EXTENT_DATA_REF_KEY: case BTRFS_EXTENT_DATA_REF_KEY:
dref = (struct btrfs_extent_data_ref *)(&iref->offset); dref = (struct btrfs_extent_data_ref *)(&iref->offset);
...@@ -117,12 +126,18 @@ static void print_extent_item(struct extent_buffer *eb, int slot, int type) ...@@ -117,12 +126,18 @@ static void print_extent_item(struct extent_buffer *eb, int slot, int type)
break; break;
case BTRFS_SHARED_DATA_REF_KEY: case BTRFS_SHARED_DATA_REF_KEY:
sref = (struct btrfs_shared_data_ref *)(iref + 1); sref = (struct btrfs_shared_data_ref *)(iref + 1);
pr_info("\t\tshared data backref parent %llu count %u\n", pr_cont("shared data backref parent %llu count %u\n",
offset, btrfs_shared_data_ref_count(eb, sref)); offset, btrfs_shared_data_ref_count(eb, sref));
/*
* offset is supposed to be a tree block which
* must be aligned to nodesize.
*/
if (!IS_ALIGNED(offset, eb->fs_info->nodesize))
pr_info("\t\t\t(parent %llu is NOT ALIGNED to nodesize %llu)\n",
offset, (unsigned long long)eb->fs_info->nodesize);
break; break;
default: default:
btrfs_err(eb->fs_info, pr_cont("(extent %llu has INVALID ref type %d)\n",
"extent %llu has invalid ref type %d",
eb->start, type); eb->start, type);
return; return;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment