| From: Liu Bo <bo.li.liu@oracle.com> |
| Date: Tue, 23 Aug 2016 15:22:58 -0700 |
| Subject: Btrfs: detect corruption when non-root leaf has zero item |
| |
| commit 1ba98d086fe3a14d6a31f2f66dbab70c45d00f63 upstream. |
| |
| Right now we treat leaf which has zero item as a valid one |
| because we could have an empty tree, that is, a root that is |
| also a leaf without any item, however, in the same case but |
| when the leaf is not a root, we can end up with hitting the |
| BUG_ON(1) in btrfs_extend_item() called by |
| setup_inline_extent_backref(). |
| |
| This makes us check the situation as a corruption if leaf is |
| not its own root. |
| |
| Signed-off-by: Liu Bo <bo.li.liu@oracle.com> |
| Reviewed-by: David Sterba <dsterba@suse.com> |
| Signed-off-by: David Sterba <dsterba@suse.com> |
| Signed-off-by: Chris Mason <clm@fb.com> |
| Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| Signed-off-by: Ben Hutchings <ben@decadent.org.uk> |
| --- |
| fs/btrfs/disk-io.c | 23 ++++++++++++++++++++++- |
| 1 file changed, 22 insertions(+), 1 deletion(-) |
| |
| --- a/fs/btrfs/disk-io.c |
| +++ b/fs/btrfs/disk-io.c |
| @@ -520,8 +520,29 @@ static noinline int check_leaf(struct bt |
| u32 nritems = btrfs_header_nritems(leaf); |
| int slot; |
| |
| - if (nritems == 0) |
| + if (nritems == 0) { |
| + struct btrfs_root *check_root; |
| + |
| + key.objectid = btrfs_header_owner(leaf); |
| + key.type = BTRFS_ROOT_ITEM_KEY; |
| + key.offset = (u64)-1; |
| + |
| + check_root = btrfs_get_fs_root(root->fs_info, &key, false); |
| + /* |
| + * The only reason we also check NULL here is that during |
| + * open_ctree() some roots has not yet been set up. |
| + */ |
| + if (!IS_ERR_OR_NULL(check_root)) { |
| + /* if leaf is the root, then it's fine */ |
| + if (leaf->start != |
| + btrfs_root_bytenr(&check_root->root_item)) { |
| + CORRUPT("non-root leaf's nritems is 0", |
| + leaf, root, 0); |
| + return -EIO; |
| + } |
| + } |
| return 0; |
| + } |
| |
| /* Check the 0 item */ |
| if (btrfs_item_offset_nr(leaf, 0) + btrfs_item_size_nr(leaf, 0) != |