Currently if there's any corruption at all in extent tree (eg. even single bit) then mounting will fail with: "failed to read block groups: -5" (-EIO) It happens because we immediately abort on first error when searching in extent tree for block groups.
Now with this patch if `ignorebadroots` option is specified then we handle such case and continue by removing already created block groups and creating dummy block groups. Signed-off-by: Dāvis Mosāns <davis...@gmail.com> --- fs/btrfs/block-group.c | 14 ++++++++++++++ fs/btrfs/disk-io.c | 4 ++-- fs/btrfs/disk-io.h | 2 ++ 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/fs/btrfs/block-group.c b/fs/btrfs/block-group.c index 48ebc106a606..827a977614b3 100644 --- a/fs/btrfs/block-group.c +++ b/fs/btrfs/block-group.c @@ -2048,6 +2048,20 @@ int btrfs_read_block_groups(struct btrfs_fs_info *info) ret = check_chunk_block_group_mappings(info); error: btrfs_free_path(path); + + if (ret == -EIO && btrfs_test_opt(info, IGNOREBADROOTS)) { + btrfs_put_block_group_cache(info); + btrfs_stop_all_workers(info); + btrfs_free_block_groups(info); + ret = btrfs_init_workqueues(info, NULL); + if (ret) + return ret; + ret = btrfs_init_space_info(info); + if (ret) + return ret; + return fill_dummy_bgs(info); + } + return ret; } diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 07a2b4f69b10..dc744f76d075 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -1955,7 +1955,7 @@ static int read_backup_root(struct btrfs_fs_info *fs_info, u8 priority) } /* helper to cleanup workers */ -static void btrfs_stop_all_workers(struct btrfs_fs_info *fs_info) +void btrfs_stop_all_workers(struct btrfs_fs_info *fs_info) { btrfs_destroy_workqueue(fs_info->fixup_workers); btrfs_destroy_workqueue(fs_info->delalloc_workers); @@ -2122,7 +2122,7 @@ static void btrfs_init_qgroup(struct btrfs_fs_info *fs_info) mutex_init(&fs_info->qgroup_rescan_lock); } -static int btrfs_init_workqueues(struct btrfs_fs_info *fs_info, +int btrfs_init_workqueues(struct btrfs_fs_info *fs_info, struct btrfs_fs_devices *fs_devices) { u32 max_active = fs_info->thread_pool_size; diff --git a/fs/btrfs/disk-io.h b/fs/btrfs/disk-io.h index e45057c0c016..f9bfcba86a04 100644 --- a/fs/btrfs/disk-io.h +++ b/fs/btrfs/disk-io.h @@ -137,6 +137,8 @@ int btrfs_find_free_objectid(struct btrfs_root *root, u64 *objectid); int btrfs_find_highest_objectid(struct btrfs_root *root, u64 *objectid); int __init btrfs_end_io_wq_init(void); void __cold btrfs_end_io_wq_exit(void); +void btrfs_stop_all_workers(struct btrfs_fs_info *fs_info); +int btrfs_init_workqueues(struct btrfs_fs_info *fs_info, struct btrfs_fs_devices *fs_devices); #ifdef CONFIG_DEBUG_LOCK_ALLOC void btrfs_set_buffer_lockdep_class(u64 objectid, -- 2.30.2