Re: [PATCH 1/3] btrfs: avoid NULL pointer dereference when block group tree root is missing

Qu Wenruo <[email protected]>
Newsgroups org.kernel.vger.linux-btrfs
Message-ID <[email protected]>

在 2026/7/11 14:49, Dongjiang Zhu 写道:
> [BUG]
> For a filesystem using the block group tree feature, corrupting the block
> group tree root and mounting with rescue=ibadroots triggers the following
> NULL pointer dereference:
> 
>    BTRFS warning (device loop0 state E): checksum verify failed on logical 30654464 mirror 1 wanted 0x0f55b851 found 0xd7efdde7 level 0
>    BTRFS warning (device loop0 state E): checksum verify failed on logical 30654464 mirror 2 wanted 0x0f55b851 found 0xd7efdde7 level 0
>    BUG: kernel NULL pointer dereference, address: 0000000000000100
>    #PF: supervisor read access in kernel mode
>    #PF: error_code(0x0000) - not-present page
>    Oops: Oops: 0000 [#1] SMP NOPTI
>    RIP: 0010:btrfs_update_global_block_rsv+0x9d/0x1c0 [btrfs]

The problem is why we need to use global block rsv in the first place?

The whole fs is never going to be mounted RW as long as "rescue=" mount 
option is utilized.

In the case of a rescue mount, we should just fill in a dummy block rsv, 
with block_rsv->full set.

This will also fix the next bug you're fixing.

>    Call Trace:
>     fill_dummy_bgs+0xd4/0x120 [btrfs]
>     open_ctree+0xc6e/0x1ca0 [btrfs]
>     btrfs_get_tree+0x50d/0xa40 [btrfs]
> 
> [CAUSE]
> With rescue=ibadroots, btrfs_read_roots() ignores a failure to read the
> block group tree root and leaves fs_info->block_group_root NULL.
> 
> btrfs_read_block_groups() then falls back to fill_dummy_bgs(), which
> initializes the global block reserve.  btrfs_update_global_block_rsv()
> checks only the BLOCK_GROUP_TREE feature bit before dereferencing
> fs_info->block_group_root.
> 
> [FIX]
> Check that the block group tree root was successfully loaded before
> accounting it in the global block reserve.  This does not affect regular
> mounts, which fail earlier if the root cannot be loaded.
> 
> Also update the comment in btrfs_read_block_groups() to cover both the
> extent tree root and the block group tree root being missing.
> 
> Fixes: 8dbfc14fc736 ("btrfs: account block group tree when calculating global reserve size")
> Signed-off-by: Dongjiang Zhu <[email protected]>
> ---
>   fs/btrfs/block-group.c | 7 ++++---
>   fs/btrfs/block-rsv.c   | 3 ++-
>   2 files changed, 6 insertions(+), 4 deletions(-)
> 
> diff --git a/fs/btrfs/block-group.c b/fs/btrfs/block-group.c
> index fe5de4928f6f..9d551372f37f 100644
> --- a/fs/btrfs/block-group.c
> +++ b/fs/btrfs/block-group.c
> @@ -2673,9 +2673,10 @@ int btrfs_read_block_groups(struct btrfs_fs_info *info)
>   	u64 cache_gen;
>   
>   	/*
> -	 * Either no extent root (with ibadroots rescue option) or we have
> -	 * unsupported RO options. The fs can never be mounted read-write, so no
> -	 * need to waste time searching block group items.
> +	 * Either the extent tree root or the block group tree root is missing
> +	 * (with the ibadroots rescue option), or we have unsupported RO options.
> +	 * The fs can never be mounted read-write, so no need to waste time
> +	 * searching block group items.
>   	 *
>   	 * This also allows new extent tree related changes to be RO compat,
>   	 * no need for a full incompat flag.
> diff --git a/fs/btrfs/block-rsv.c b/fs/btrfs/block-rsv.c
> index 9efb3016ef11..647a065356f4 100644
> --- a/fs/btrfs/block-rsv.c
> +++ b/fs/btrfs/block-rsv.c
> @@ -347,7 +347,8 @@ void btrfs_update_global_block_rsv(struct btrfs_fs_info *fs_info)
>   	}
>   	read_unlock(&fs_info->global_root_lock);
>   
> -	if (btrfs_fs_compat_ro(fs_info, BLOCK_GROUP_TREE)) {
> +	if (btrfs_fs_compat_ro(fs_info, BLOCK_GROUP_TREE) &&
> +	    fs_info->block_group_root) {
>   		num_bytes += btrfs_root_used(&fs_info->block_group_root->root_item);
>   		min_items++;
>   	}
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.