From: Qu Wenruo <wqu@suse.com>
To: ZhengYuan Huang <gality369@gmail.com>,
dsterba@suse.com, clm@fb.com, zheng.yan@oracle.com
Cc: linux-btrfs@vger.kernel.org, linux-kernel@vger.kernel.org,
baijiaju1990@gmail.com, r33s3n6@gmail.com, zzzccc427@gmail.com
Subject: Re: [PATCH] btrfs: treat empty left leaf as corruption in push_leaf_left()
Date: Thu, 9 Apr 2026 17:20:56 +0930 [thread overview]
Message-ID: <fdc220ea-8f1f-45e4-9851-5eaaf8051153@suse.com> (raw)
In-Reply-To: <20260409071255.3358044-1-gality369@gmail.com>
在 2026/4/9 16:42, ZhengYuan Huang 写道:
> [BUG]
> A corrupted tree can leave a non-root leaf with 0 items linked from its
> parent. When btrfs_del_items() later tries to rebalance a right leaf into
> that left sibling, push_leaf_left() passes the empty leaf down and we hit:
>
> kernel BUG at fs/btrfs/ctree.c:3388!
> Oops: invalid opcode: 0000 [#1] SMP KASAN NOPTI
> RIP: 0010:__push_leaf_left+0x11f8/0x1610 fs/btrfs/ctree.c:3388
> Code: ff48c1ea 03803c02 000f85bd 00000048
> Call Trace:
> push_leaf_left+0x3b3/0x540 fs/btrfs/ctree.c:3511
> btrfs_del_items+0x74d/0xf10 fs/btrfs/ctree.c:4541
> btrfs_del_csums+0x44d/0xa50 fs/btrfs/file-item.c:969
> do_free_extent_accounting fs/btrfs/extent-tree.c:2984 [inline]
> __btrfs_free_extent.isra.0+0xded/0x41d0 fs/btrfs/extent-tree.c:3372
> run_delayed_data_ref fs/btrfs/extent-tree.c:1599 [inline]
> run_one_delayed_ref fs/btrfs/extent-tree.c:1779 [inline]
> btrfs_run_delayed_refs_for_head fs/btrfs/extent-tree.c:1972 [inline]
> __btrfs_run_delayed_refs+0x86e/0x39a0 fs/btrfs/extent-tree.c:2047
> btrfs_run_delayed_refs+0x181/0x420 fs/btrfs/extent-tree.c:2159
> btrfs_commit_transaction+0xc9b/0x3d90 fs/btrfs/transaction.c:2211
> btrfs_sync_fs+0xf0/0x630 fs/btrfs/super.c:1057
> sync_fs_one_sb fs/sync.c:84 [inline]
> sync_fs_one_sb+0xf4/0x140 fs/sync.c:80
> __iterate_supers+0x1be/0x290 fs/super.c:923
> iterate_supers+0x24/0x40 fs/super.c:938
> ksys_sync+0xb4/0x160 fs/sync.c:104
> __do_sys_sync+0x13/0x20 fs/sync.c:113
> ...
>
> [CAUSE]
> push_leaf_left() only checks how much free space the left sibling has.
> An empty leaf has maximum free space, so it passes that test. The sibling
> key validation also skips empty leaves because there are no keys to
> compare, allowing the empty leaf to reach __push_leaf_left().
>
> [FIX]
> Detect an empty left sibling leaf in push_leaf_left() and treat it as tree
> corruption. Abort the transaction with -EUCLEAN before modifying either
> leaf, which avoids the BUG_ON() and matches how other unexpected btree
> states are handled in btrfs.
>
> Fixes: 87b29b208c6c ("Btrfs: properly check free space for tree balancing")
> Signed-off-by: ZhengYuan Huang <gality369@gmail.com>
> ---
> fs/btrfs/ctree.c | 9 +++++++++
> 1 file changed, 9 insertions(+)
>
> diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
> index 561658aca018..625aa2ab4c5b 100644
> --- a/fs/btrfs/ctree.c
> +++ b/fs/btrfs/ctree.c
> @@ -3486,6 +3486,15 @@ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root
> return PTR_ERR(left);
>
> btrfs_tree_lock_nested(left, BTRFS_NESTING_LEFT);
> + /* An empty non-root leaf means the tree is corrupted. */
> + if (unlikely(btrfs_header_nritems(left) == 0)) {
> + btrfs_crit(left->fs_info,
> + "empty left leaf at bytenr %llu while pushing from right leaf %llu",
> + left->start, right->start);
> + ret = -EUCLEAN;
> + btrfs_abort_transaction(trans, ret);
> + goto out;
> + }
I think the timing is too late, and if there is an non-root empty leaf
but we never modified it, kernel will not detect it.
I'd recommend to reject such empty leaves at
btrfs_validate_extent_buffer(), if we have check->has_first_key, then
the leaf should not be empty.
Thanks,
Qu
>
> free_space = btrfs_leaf_free_space(left);
> if (free_space < data_size) {
next prev parent reply other threads:[~2026-04-09 7:51 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-09 7:12 [PATCH] btrfs: treat empty left leaf as corruption in push_leaf_left() ZhengYuan Huang
2026-04-09 7:50 ` Qu Wenruo [this message]
2026-04-09 8:01 ` ZhengYuan Huang
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=fdc220ea-8f1f-45e4-9851-5eaaf8051153@suse.com \
--to=wqu@suse.com \
--cc=baijiaju1990@gmail.com \
--cc=clm@fb.com \
--cc=dsterba@suse.com \
--cc=gality369@gmail.com \
--cc=linux-btrfs@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=r33s3n6@gmail.com \
--cc=zheng.yan@oracle.com \
--cc=zzzccc427@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox