mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Siddharth Mishra <smish149@asu.edu>
To: dsterba@suse.com
Cc: mason@kernel.org, josef@toxicpanda.com, wqu@suse.com,
	fdmanana@kernel.org, linux-btrfs@vger.kernel.org,
	linux-kernel@vger.kernel.org, Siddharth Mishra <smish149@asu.edu>
Subject: [PATCH 2/2] btrfs: tree-checker: add balance item size check
Date: Thu,  5 Nov 2026 14:47:38 -0700	[thread overview]
Message-ID: <20261105214738.111967-3-smish149@asu.edu> (raw)
In-Reply-To: <20261105214738.111967-1-smish149@asu.edu>

[BACKGROUND]
A paused or interrupted balance leaves a balance item in the root tree,
with the key (BALANCE_OBJECTID TEMPORARY_ITEM 0) and a struct
btrfs_balance_item of 448 bytes.  At mount btrfs_recover_balance()
reads the flags and the data, meta and sys args from this item, and
the balance is resumed with them.

[CAUSE]
The tree-checker has no check for TEMPORARY_ITEM keys, and
btrfs_recover_balance() reads the item without checking its size.
With a balance item that is too short, the reads go past the end of
the item into the data of the previous item in the leaf, and the
balance is resumed with whatever those bytes hold.  Nothing is
reported.  For example this balance item is 48 bytes short:

  item 11 key (DATA_RELOC_TREE ROOT_ITEM 0) itemoff 12545 itemsize 439
  item 12 key (BALANCE TEMPORARY_ITEM 0) itemoff 12145 itemsize 400
                                                       ^^^^^^^^^^^^

The mount succeeds and the balance is resumed:

  BTRFS info (device vda): balance: resume
  BTRFS info (device vda): balance: ended with status: 0

[ENHANCEMENT]
Add check_balance_item() to reject a balance item whose size is not
the size of struct btrfs_balance_item, so the leaf is refused when it
is read:

  BTRFS critical (device vda): corrupt leaf: root=1 block=30654464
  slot=12, invalid balance item size, have 400 expect 448
  BTRFS error (device vda): read time tree block corruption detected
  on logical 30654464 mirror 1
  BTRFS warning (device vda): couldn't read tree root
  BTRFS error (device vda): open_ctree failed: -EIO

Signed-off-by: Siddharth Mishra <smish149@asu.edu>
---
An alternative is to check the size only where the item is read, in
btrfs_recover_balance(), before bctl is allocated.  That refuses only
the balance item and fails the mount with -EUCLEAN, instead of refusing
the whole root tree leaf:

  BTRFS error (device vda): invalid balance item size, have 400 expect 448
  BTRFS error (device vda): failed to recover balance: -EUCLEAN
  BTRFS error (device vda): open_ctree failed: -EUCLEAN

It was tested the same way as this patch.  The tested diff, indented so
that it is not applied with this patch, in case it is preferred:

  diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
  index 3d4ef6725..97154f59f 100644
  --- a/fs/btrfs/volumes.c
  +++ b/fs/btrfs/volumes.c
  @@ -5230,11 +5230,17 @@ int btrfs_recover_balance(struct btrfs_fs_info *fs_info)
   		return 0;
   	}
   
  +	leaf = path->nodes[0];
  +	if (unlikely(btrfs_item_size(leaf, path->slots[0]) != sizeof(*item))) {
  +		btrfs_err(fs_info, "invalid balance item size, have %u expect %zu",
  +			  btrfs_item_size(leaf, path->slots[0]), sizeof(*item));
  +		return -EUCLEAN;
  +	}
  +
   	bctl = kzalloc_obj(*bctl, GFP_NOFS);
   	if (!bctl)
   		return -ENOMEM;
   
  -	leaf = path->nodes[0];
   	item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_balance_item);
   
   	bctl->flags = btrfs_balance_flags(leaf, item);

 fs/btrfs/tree-checker.c | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/fs/btrfs/tree-checker.c b/fs/btrfs/tree-checker.c
index f021ac14b..5698845be 100644
--- a/fs/btrfs/tree-checker.c
+++ b/fs/btrfs/tree-checker.c
@@ -2117,6 +2117,19 @@ static int check_qgroup_status_item(const struct extent_buffer *leaf, int slot)
 	return 0;
 }
 
+static int check_balance_item(const struct extent_buffer *leaf, int slot)
+{
+	const u32 item_size = btrfs_item_size(leaf, slot);
+
+	if (unlikely(item_size != sizeof(struct btrfs_balance_item))) {
+		generic_err(leaf, slot,
+			    "invalid balance item size, have %u expect %zu",
+			    item_size, sizeof(struct btrfs_balance_item));
+		return -EUCLEAN;
+	}
+	return 0;
+}
+
 static int check_remap_key(const struct extent_buffer *leaf,
 			   const struct btrfs_key *key, int slot)
 {
@@ -2512,6 +2525,10 @@ static enum btrfs_tree_block_status check_leaf_item(struct extent_buffer *leaf,
 	case BTRFS_QGROUP_STATUS_KEY:
 		ret = check_qgroup_status_item(leaf, slot);
 		break;
+	case BTRFS_TEMPORARY_ITEM_KEY:
+		if (key->objectid == BTRFS_BALANCE_OBJECTID)
+			ret = check_balance_item(leaf, slot);
+		break;
 	case BTRFS_IDENTITY_REMAP_KEY:
 	case BTRFS_REMAP_KEY:
 	case BTRFS_REMAP_BACKREF_KEY:
-- 
2.54.0


  parent reply	other threads:[~2026-11-05 21:47 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-05 21:47 [PATCH 0/2] btrfs: balance item fixes Siddharth Mishra
2026-11-05 21:47 ` [PATCH 1/2] btrfs: overwrite a leftover balance item instead of BUG_ON() Siddharth Mishra
2026-11-05 22:09   ` Qu Wenruo
2026-11-05 22:40     ` Siddharth Mishra
2026-11-05 22:43       ` Qu Wenruo
2026-11-05 21:47 ` Siddharth Mishra [this message]
2026-11-05 22:06   ` [PATCH 2/2] btrfs: tree-checker: add balance item size check Qu Wenruo

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=20261105214738.111967-3-smish149@asu.edu \
    --to=smish149@asu.edu \
    --cc=dsterba@suse.com \
    --cc=fdmanana@kernel.org \
    --cc=josef@toxicpanda.com \
    --cc=linux-btrfs@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mason@kernel.org \
    --cc=wqu@suse.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

all inboxes | Powered by JetHome®