diff options
author | Liu Bo <bo.li.liu@oracle.com> | 2016-08-23 20:37:45 -0400 |
---|---|---|
committer | Chris Mason <clm@fb.com> | 2016-08-25 06:58:30 -0400 |
commit | 053ab70f0604224c7893b43f9d9d5efa283580d6 (patch) | |
tree | 7f2ac232c96eafbfbc71a85337ad935d9e599473 | |
parent | 35bbb97fc898aeb874cb7c8b746f091caa359994 (diff) |
Btrfs: check btree node's nritems
When btree node (level = 1) has nritems which equals to zero,
we can end up with panic due to insert_ptr()'s
BUG_ON(slot > nritems);
where slot is 1 and nritems is 0, as copy_for_split() calls
insert_ptr(.., path->slots[1] + 1, ...);
A invalid value results in the whole mess, this adds the check
for btree's node nritems so that we stop reading block when
when something is wrong.
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>
-rw-r--r-- | fs/btrfs/disk-io.c | 16 |
1 files changed, 16 insertions, 0 deletions
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index edda47162752..474209f50844 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -613,6 +613,19 @@ static noinline int check_leaf(struct btrfs_root *root, | |||
613 | return 0; | 613 | return 0; |
614 | } | 614 | } |
615 | 615 | ||
616 | static int check_node(struct btrfs_root *root, struct extent_buffer *node) | ||
617 | { | ||
618 | unsigned long nr = btrfs_header_nritems(node); | ||
619 | |||
620 | if (nr == 0 || nr > BTRFS_NODEPTRS_PER_BLOCK(root)) { | ||
621 | btrfs_crit(root->fs_info, | ||
622 | "corrupt node: block %llu root %llu nritems %lu", | ||
623 | node->start, root->objectid, nr); | ||
624 | return -EIO; | ||
625 | } | ||
626 | return 0; | ||
627 | } | ||
628 | |||
616 | static int btree_readpage_end_io_hook(struct btrfs_io_bio *io_bio, | 629 | static int btree_readpage_end_io_hook(struct btrfs_io_bio *io_bio, |
617 | u64 phy_offset, struct page *page, | 630 | u64 phy_offset, struct page *page, |
618 | u64 start, u64 end, int mirror) | 631 | u64 start, u64 end, int mirror) |
@@ -683,6 +696,9 @@ static int btree_readpage_end_io_hook(struct btrfs_io_bio *io_bio, | |||
683 | ret = -EIO; | 696 | ret = -EIO; |
684 | } | 697 | } |
685 | 698 | ||
699 | if (found_level > 0 && check_node(root, eb)) | ||
700 | ret = -EIO; | ||
701 | |||
686 | if (!ret) | 702 | if (!ret) |
687 | set_extent_buffer_uptodate(eb); | 703 | set_extent_buffer_uptodate(eb); |
688 | err: | 704 | err: |