public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: ZhengYuan Huang <gality369@gmail.com>
To: 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,
	ZhengYuan Huang <gality369@gmail.com>
Subject: [PATCH] btrfs: treat empty left leaf as corruption in push_leaf_left()
Date: Thu,  9 Apr 2026 15:12:55 +0800	[thread overview]
Message-ID: <20260409071255.3358044-1-gality369@gmail.com> (raw)

[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;
+	}
 
 	free_space = btrfs_leaf_free_space(left);
 	if (free_space < data_size) {
-- 
2.43.0

             reply	other threads:[~2026-04-09  7:13 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-04-09  7:12 ZhengYuan Huang [this message]
2026-04-09  7:50 ` [PATCH] btrfs: treat empty left leaf as corruption in push_leaf_left() Qu Wenruo
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=20260409071255.3358044-1-gality369@gmail.com \
    --to=gality369@gmail.com \
    --cc=baijiaju1990@gmail.com \
    --cc=clm@fb.com \
    --cc=dsterba@suse.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