From a4f78750ef1882e59bb4f947e216cf61ef2d67d2 Mon Sep 17 00:00:00 2001 From: David Sterba Date: Thu, 29 Jun 2017 18:37:49 +0200 Subject: btrfs: get fs_info from eb in btrfs_print_leaf, remove argument Signed-off-by: David Sterba --- fs/btrfs/print-tree.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'fs/btrfs/print-tree.c') diff --git a/fs/btrfs/print-tree.c b/fs/btrfs/print-tree.c index fcae61e175f3..9c3911f4a100 100644 --- a/fs/btrfs/print-tree.c +++ b/fs/btrfs/print-tree.c @@ -161,8 +161,9 @@ static void print_uuid_item(struct extent_buffer *l, unsigned long offset, } } -void btrfs_print_leaf(struct btrfs_fs_info *fs_info, struct extent_buffer *l) +void btrfs_print_leaf(struct extent_buffer *l) { + struct btrfs_fs_info *fs_info; int i; u32 type, nr; struct btrfs_item *item; @@ -180,6 +181,7 @@ void btrfs_print_leaf(struct btrfs_fs_info *fs_info, struct extent_buffer *l) if (!l) return; + fs_info = l->fs_info; nr = btrfs_header_nritems(l); btrfs_info(fs_info, "leaf %llu total ptrs %d free space %d", @@ -329,7 +331,7 @@ void btrfs_print_tree(struct btrfs_fs_info *fs_info, struct extent_buffer *c) nr = btrfs_header_nritems(c); level = btrfs_header_level(c); if (level == 0) { - btrfs_print_leaf(fs_info, c); + btrfs_print_leaf(c); return; } btrfs_info(fs_info, -- cgit v1.2.3 From abe60ba45c145db2d90609138755fbb3dbc47d00 Mon Sep 17 00:00:00 2001 From: David Sterba Date: Thu, 29 Jun 2017 18:37:49 +0200 Subject: btrfs: get fs_info from eb in btrfs_print_tree, remove argument Signed-off-by: David Sterba --- fs/btrfs/print-tree.c | 6 ++++-- fs/btrfs/print-tree.h | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'fs/btrfs/print-tree.c') diff --git a/fs/btrfs/print-tree.c b/fs/btrfs/print-tree.c index 9c3911f4a100..6e7a8c40dcd9 100644 --- a/fs/btrfs/print-tree.c +++ b/fs/btrfs/print-tree.c @@ -320,14 +320,16 @@ void btrfs_print_leaf(struct extent_buffer *l) } } -void btrfs_print_tree(struct btrfs_fs_info *fs_info, struct extent_buffer *c) +void btrfs_print_tree(struct extent_buffer *c) { + struct btrfs_fs_info *fs_info; int i; u32 nr; struct btrfs_key key; int level; if (!c) return; + fs_info = c->fs_info; nr = btrfs_header_nritems(c); level = btrfs_header_level(c); if (level == 0) { @@ -361,7 +363,7 @@ void btrfs_print_tree(struct btrfs_fs_info *fs_info, struct extent_buffer *c) if (btrfs_header_level(next) != level - 1) BUG(); - btrfs_print_tree(fs_info, next); + btrfs_print_tree(next); free_extent_buffer(next); } } diff --git a/fs/btrfs/print-tree.h b/fs/btrfs/print-tree.h index 689a52ee0cd1..3afd508ed8c5 100644 --- a/fs/btrfs/print-tree.h +++ b/fs/btrfs/print-tree.h @@ -19,5 +19,5 @@ #ifndef __PRINT_TREE_ #define __PRINT_TREE_ void btrfs_print_leaf(struct extent_buffer *l); -void btrfs_print_tree(struct btrfs_fs_info *fs_info, struct extent_buffer *c); +void btrfs_print_tree(struct extent_buffer *c); #endif -- cgit v1.2.3 From 07638ea5987e51715b35eb5a9a9e908f18ffabf7 Mon Sep 17 00:00:00 2001 From: Liu Bo Date: Fri, 18 Aug 2017 15:15:21 -0600 Subject: Btrfs: remove BUG() in print_extent_item btrfs_print_leaf() is used in btrfs_get_extent_inline_ref_type, so here we really want to print the invalid value of ref type instead of causing a kernel panic. Signed-off-by: Liu Bo Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/print-tree.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'fs/btrfs/print-tree.c') diff --git a/fs/btrfs/print-tree.c b/fs/btrfs/print-tree.c index 6e7a8c40dcd9..c1acbdcb476c 100644 --- a/fs/btrfs/print-tree.c +++ b/fs/btrfs/print-tree.c @@ -121,7 +121,10 @@ static void print_extent_item(struct extent_buffer *eb, int slot, int type) offset, btrfs_shared_data_ref_count(eb, sref)); break; default: - BUG(); + btrfs_err(eb->fs_info, + "extent %llu has invalid ref type %d", + eb->start, type); + return; } ptr += btrfs_extent_inline_ref_size(type); } -- cgit v1.2.3 From 64ecdb647ddb83dcff9c8e2a5c40119f171ea004 Mon Sep 17 00:00:00 2001 From: Liu Bo Date: Fri, 18 Aug 2017 15:15:24 -0600 Subject: 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: Liu Bo Signed-off-by: David Sterba --- fs/btrfs/extent-tree.c | 29 +++++++++++++++++++++++++---- fs/btrfs/print-tree.c | 27 +++++++++++++++++++++------ 2 files changed, 46 insertions(+), 10 deletions(-) (limited to 'fs/btrfs/print-tree.c') diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 51a691532fd8..96e49fd5b888 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -1158,19 +1158,40 @@ int btrfs_get_extent_inline_ref_type(const struct extent_buffer *eb, enum btrfs_inline_ref_type is_data) { 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 || type == BTRFS_SHARED_BLOCK_REF_KEY || type == BTRFS_SHARED_DATA_REF_KEY || type == BTRFS_EXTENT_DATA_REF_KEY) { if (is_data == BTRFS_REF_TYPE_BLOCK) { - if (type == BTRFS_TREE_BLOCK_REF_KEY || - type == BTRFS_SHARED_BLOCK_REF_KEY) + if (type == BTRFS_TREE_BLOCK_REF_KEY) 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) { - if (type == BTRFS_EXTENT_DATA_REF_KEY || - type == BTRFS_SHARED_DATA_REF_KEY) + if (type == BTRFS_EXTENT_DATA_REF_KEY) 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 { ASSERT(is_data == BTRFS_REF_TYPE_ANY); return type; diff --git a/fs/btrfs/print-tree.c b/fs/btrfs/print-tree.c index c1acbdcb476c..569205e651c7 100644 --- a/fs/btrfs/print-tree.c +++ b/fs/btrfs/print-tree.c @@ -44,7 +44,7 @@ static void print_dev_item(struct extent_buffer *eb, static void print_extent_data_ref(struct extent_buffer *eb, 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_objectid(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) u32 item_size = btrfs_item_size_nr(eb, slot); u64 flags; u64 offset; + int ref_index = 0; if (item_size < sizeof(*ei)) { #ifdef BTRFS_COMPAT_EXTENT_TREE_V0 @@ -104,12 +105,20 @@ static void print_extent_item(struct extent_buffer *eb, int slot, int type) iref = (struct btrfs_extent_inline_ref *)ptr; type = btrfs_extent_inline_ref_type(eb, iref); offset = btrfs_extent_inline_ref_offset(eb, iref); + pr_info("\t\tref#%d: ", ref_index++); switch (type) { 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; 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; case BTRFS_EXTENT_DATA_REF_KEY: 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) break; case BTRFS_SHARED_DATA_REF_KEY: 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 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; default: - btrfs_err(eb->fs_info, - "extent %llu has invalid ref type %d", + pr_cont("(extent %llu has INVALID ref type %d)\n", eb->start, type); return; } -- cgit v1.2.3