diff options
Diffstat (limited to 'fs/btrfs/disk-io.c')
-rw-r--r-- | fs/btrfs/disk-io.c | 56 |
1 files changed, 51 insertions, 5 deletions
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 59febfb8d04a..54bc8c7c6bcd 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -559,8 +559,29 @@ static noinline int check_leaf(struct btrfs_root *root, | |||
559 | u32 nritems = btrfs_header_nritems(leaf); | 559 | u32 nritems = btrfs_header_nritems(leaf); |
560 | int slot; | 560 | int slot; |
561 | 561 | ||
562 | if (nritems == 0) | 562 | if (nritems == 0) { |
563 | struct btrfs_root *check_root; | ||
564 | |||
565 | key.objectid = btrfs_header_owner(leaf); | ||
566 | key.type = BTRFS_ROOT_ITEM_KEY; | ||
567 | key.offset = (u64)-1; | ||
568 | |||
569 | check_root = btrfs_get_fs_root(root->fs_info, &key, false); | ||
570 | /* | ||
571 | * The only reason we also check NULL here is that during | ||
572 | * open_ctree() some roots has not yet been set up. | ||
573 | */ | ||
574 | if (!IS_ERR_OR_NULL(check_root)) { | ||
575 | /* if leaf is the root, then it's fine */ | ||
576 | if (leaf->start != | ||
577 | btrfs_root_bytenr(&check_root->root_item)) { | ||
578 | CORRUPT("non-root leaf's nritems is 0", | ||
579 | leaf, root, 0); | ||
580 | return -EIO; | ||
581 | } | ||
582 | } | ||
563 | return 0; | 583 | return 0; |
584 | } | ||
564 | 585 | ||
565 | /* Check the 0 item */ | 586 | /* Check the 0 item */ |
566 | if (btrfs_item_offset_nr(leaf, 0) + btrfs_item_size_nr(leaf, 0) != | 587 | if (btrfs_item_offset_nr(leaf, 0) + btrfs_item_size_nr(leaf, 0) != |
@@ -612,6 +633,19 @@ static noinline int check_leaf(struct btrfs_root *root, | |||
612 | return 0; | 633 | return 0; |
613 | } | 634 | } |
614 | 635 | ||
636 | static int check_node(struct btrfs_root *root, struct extent_buffer *node) | ||
637 | { | ||
638 | unsigned long nr = btrfs_header_nritems(node); | ||
639 | |||
640 | if (nr == 0 || nr > BTRFS_NODEPTRS_PER_BLOCK(root)) { | ||
641 | btrfs_crit(root->fs_info, | ||
642 | "corrupt node: block %llu root %llu nritems %lu", | ||
643 | node->start, root->objectid, nr); | ||
644 | return -EIO; | ||
645 | } | ||
646 | return 0; | ||
647 | } | ||
648 | |||
615 | static int btree_readpage_end_io_hook(struct btrfs_io_bio *io_bio, | 649 | static int btree_readpage_end_io_hook(struct btrfs_io_bio *io_bio, |
616 | u64 phy_offset, struct page *page, | 650 | u64 phy_offset, struct page *page, |
617 | u64 start, u64 end, int mirror) | 651 | u64 start, u64 end, int mirror) |
@@ -682,6 +716,9 @@ static int btree_readpage_end_io_hook(struct btrfs_io_bio *io_bio, | |||
682 | ret = -EIO; | 716 | ret = -EIO; |
683 | } | 717 | } |
684 | 718 | ||
719 | if (found_level > 0 && check_node(root, eb)) | ||
720 | ret = -EIO; | ||
721 | |||
685 | if (!ret) | 722 | if (!ret) |
686 | set_extent_buffer_uptodate(eb); | 723 | set_extent_buffer_uptodate(eb); |
687 | err: | 724 | err: |
@@ -1618,8 +1655,8 @@ fail: | |||
1618 | return ret; | 1655 | return ret; |
1619 | } | 1656 | } |
1620 | 1657 | ||
1621 | static struct btrfs_root *btrfs_lookup_fs_root(struct btrfs_fs_info *fs_info, | 1658 | struct btrfs_root *btrfs_lookup_fs_root(struct btrfs_fs_info *fs_info, |
1622 | u64 root_id) | 1659 | u64 root_id) |
1623 | { | 1660 | { |
1624 | struct btrfs_root *root; | 1661 | struct btrfs_root *root; |
1625 | 1662 | ||
@@ -2298,6 +2335,7 @@ static void btrfs_init_qgroup(struct btrfs_fs_info *fs_info) | |||
2298 | fs_info->quota_enabled = 0; | 2335 | fs_info->quota_enabled = 0; |
2299 | fs_info->pending_quota_state = 0; | 2336 | fs_info->pending_quota_state = 0; |
2300 | fs_info->qgroup_ulist = NULL; | 2337 | fs_info->qgroup_ulist = NULL; |
2338 | fs_info->qgroup_rescan_running = false; | ||
2301 | mutex_init(&fs_info->qgroup_rescan_lock); | 2339 | mutex_init(&fs_info->qgroup_rescan_lock); |
2302 | } | 2340 | } |
2303 | 2341 | ||
@@ -2624,6 +2662,7 @@ int open_ctree(struct super_block *sb, | |||
2624 | atomic_set(&fs_info->qgroup_op_seq, 0); | 2662 | atomic_set(&fs_info->qgroup_op_seq, 0); |
2625 | atomic_set(&fs_info->reada_works_cnt, 0); | 2663 | atomic_set(&fs_info->reada_works_cnt, 0); |
2626 | atomic64_set(&fs_info->tree_mod_seq, 0); | 2664 | atomic64_set(&fs_info->tree_mod_seq, 0); |
2665 | fs_info->fs_frozen = 0; | ||
2627 | fs_info->sb = sb; | 2666 | fs_info->sb = sb; |
2628 | fs_info->max_inline = BTRFS_DEFAULT_MAX_INLINE; | 2667 | fs_info->max_inline = BTRFS_DEFAULT_MAX_INLINE; |
2629 | fs_info->metadata_ratio = 0; | 2668 | fs_info->metadata_ratio = 0; |
@@ -3739,8 +3778,15 @@ void btrfs_drop_and_free_fs_root(struct btrfs_fs_info *fs_info, | |||
3739 | if (btrfs_root_refs(&root->root_item) == 0) | 3778 | if (btrfs_root_refs(&root->root_item) == 0) |
3740 | synchronize_srcu(&fs_info->subvol_srcu); | 3779 | synchronize_srcu(&fs_info->subvol_srcu); |
3741 | 3780 | ||
3742 | if (test_bit(BTRFS_FS_STATE_ERROR, &fs_info->fs_state)) | 3781 | if (test_bit(BTRFS_FS_STATE_ERROR, &fs_info->fs_state)) { |
3743 | btrfs_free_log(NULL, root); | 3782 | btrfs_free_log(NULL, root); |
3783 | if (root->reloc_root) { | ||
3784 | free_extent_buffer(root->reloc_root->node); | ||
3785 | free_extent_buffer(root->reloc_root->commit_root); | ||
3786 | btrfs_put_fs_root(root->reloc_root); | ||
3787 | root->reloc_root = NULL; | ||
3788 | } | ||
3789 | } | ||
3744 | 3790 | ||
3745 | if (root->free_ino_pinned) | 3791 | if (root->free_ino_pinned) |
3746 | __btrfs_remove_free_space_cache(root->free_ino_pinned); | 3792 | __btrfs_remove_free_space_cache(root->free_ino_pinned); |
@@ -3851,7 +3897,7 @@ void close_ctree(struct btrfs_root *root) | |||
3851 | smp_mb(); | 3897 | smp_mb(); |
3852 | 3898 | ||
3853 | /* wait for the qgroup rescan worker to stop */ | 3899 | /* wait for the qgroup rescan worker to stop */ |
3854 | btrfs_qgroup_wait_for_completion(fs_info); | 3900 | btrfs_qgroup_wait_for_completion(fs_info, false); |
3855 | 3901 | ||
3856 | /* wait for the uuid_scan task to finish */ | 3902 | /* wait for the uuid_scan task to finish */ |
3857 | down(&fs_info->uuid_tree_rescan_sem); | 3903 | down(&fs_info->uuid_tree_rescan_sem); |