public inbox for linux-btrfs@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 v2] btrfs: reject empty non-root tree blocks at read time
Date: Thu,  9 Apr 2026 16:11:40 +0800	[thread overview]
Message-ID: <20260409081140.3400650-1-gality369@gmail.com> (raw)

[BUG]
A corrupted tree can contain an empty non-root tree block linked from
its parent. If that block is later used by normal tree balancing,
btrfs can 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]
The old btrfs_verify_level_key() path rejected tree blocks with
nritems == 0 whenever the parent check provided a first key.
Commit 947a629988f1 ("btrfs: move tree block parentness check into
validate_extent_buffer()") moved the parentness checks into the read-time
validation path, but it dropped that guard. This lets an empty non-root
tree block pass read-time validation even though slot 0 must exist if the
parent provides a first key.

[FIX]
Restore the nritems == 0 rejection in btrfs_validate_extent_buffer()
when check->has_first_key is set. This rejects empty non-root tree
blocks as soon as they are read from disk, before later btree
operations can hit BUG_ONs while trying to use them.

Fixes: 947a629988f1 ("btrfs: move tree block parentness check into validate_extent_buffer()")
Signed-off-by: ZhengYuan Huang <gality369@gmail.com>
---
v2:
- Move the corruption check from push_leaf_left() to read-time validation
- Restore the old nritems == 0 guard before reading slot 0

 fs/btrfs/disk-io.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 0aa7e5d1b05f..ab2044d83155 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -430,6 +430,15 @@ int btrfs_validate_extent_buffer(struct extent_buffer *eb,
 		const struct btrfs_key *expect_key = &check->first_key;
 		struct btrfs_key found_key;
 
+		/* We have @first_key, so this @eb must have at least one item. */
+		if (unlikely(btrfs_header_nritems(eb) == 0)) {
+			btrfs_err(fs_info,
+				  "invalid tree nritems, bytenr=%llu nritems=0 expect >0",
+				  eb->start);
+			ret = -EUCLEAN;
+			goto out;
+		}
+
 		if (found_level)
 			btrfs_node_key_to_cpu(eb, &found_key, 0);
 		else
-- 
2.43.0

             reply	other threads:[~2026-04-09  8:11 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-04-09  8:11 ZhengYuan Huang [this message]
2026-04-09  9:09 ` [PATCH v2] btrfs: reject empty non-root tree blocks at read time Qu Wenruo
2026-04-09  9:38   ` Qu Wenruo
2026-04-12  3:29 ` kernel test robot
2026-04-12  4:07 ` kernel test robot
2026-04-12  4:53 ` kernel test robot

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=20260409081140.3400650-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