mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH 0/2] btrfs: balance item fixes
@ 2026-11-05 21:47 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 21:47 ` [PATCH 2/2] btrfs: tree-checker: add balance item size check Siddharth Mishra
  0 siblings, 2 replies; 7+ messages in thread
From: Siddharth Mishra @ 2026-11-05 21:47 UTC (permalink / raw)
  To: dsterba
  Cc: mason, josef, wqu, fdmanana, linux-btrfs, linux-kernel, Siddharth Mishra

Patch 1 fixes a BUG_ON() in btrfs_balance() on a valid filesystem.  A
balance can leave its item in the root tree when the commit after the
insert fails without an abort, and the next balance then finds the item
and hits BUG_ON(ret == -EEXIST).  syzbot reported it, see patch 1.  The
new balance now overwrites the item that no balance owns.

Patch 2 is hardening.  Nothing checks the size of the balance item, and
btrfs_recover_balance() reads past a short item at mount.  The
tree-checker now rejects a balance item with the wrong size.

Found while looking into a fuzzing report.  An AI tool helped with the
analysis and the patches.

Tested on btrfs for-next df5b88a7914e, KASAN and non-debug kernels:
- Patch 1: on a new filesystem, one failed allocation in
  btrfs_start_dirty_block_groups() during a first balance, then a
  second balance: the BUG_ON() before; with the patch the second
  balance runs to the end, no balance item is left and btrfs check is
  clean.  The same with a failed allocation at each of the first 206
  allocation points of the first balance: no BUG, KASAN report or
  assertion.  Not reproduced without fault injection.  The other way to
  the BUG_ON(), a transaction aborted with -EEXIST, is not reproduced
  on this base: the corrupted image that hit it is now refused by the
  tree-checker at mount.
- Patch 2: a crafted image with a 400 byte balance item is refused at
  mount; valid filesystems (a paused balance resumed or cancelled after
  mount, a balance paused and resumed) are not rejected.
- Both: pause, resume, cancel and skip_balance work as before;
  fstests -g balance and btrfs/220: no new failure.

The crafted image is available on request.

Siddharth Mishra (2):
  btrfs: overwrite a leftover balance item instead of BUG_ON()
  btrfs: tree-checker: add balance item size check

 fs/btrfs/tree-checker.c | 17 +++++++++++++++++
 fs/btrfs/volumes.c      | 10 ++++++----
 2 files changed, 23 insertions(+), 4 deletions(-)


base-commit: df5b88a7914e18488908ddf13e14e31ab39f954c
-- 
2.54.0


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 1/2] btrfs: overwrite a leftover balance item instead of BUG_ON()
  2026-11-05 21:47 [PATCH 0/2] btrfs: balance item fixes Siddharth Mishra
@ 2026-11-05 21:47 ` Siddharth Mishra
  2026-11-05 22:09   ` Qu Wenruo
  2026-11-05 21:47 ` [PATCH 2/2] btrfs: tree-checker: add balance item size check Siddharth Mishra
  1 sibling, 1 reply; 7+ messages in thread
From: Siddharth Mishra @ 2026-11-05 21:47 UTC (permalink / raw)
  To: dsterba
  Cc: mason, josef, wqu, fdmanana, linux-btrfs, linux-kernel,
	Siddharth Mishra, syzbot+dc9291cf132691aeb478, stable

[BUG]
A balance ioctl can hit this BUG_ON():

  kernel BUG at fs/btrfs/volumes.c:5088!
  Oops: invalid opcode: 0000 [#1] SMP NOPTI
  RIP: 0010:btrfs_balance (fs/btrfs/volumes.c:5088)
  Call Trace:
   <TASK>
   btrfs_ioctl (fs/btrfs/ioctl.c:3523 fs/btrfs/ioctl.c:5650)
   __x64_sys_ioctl
   do_syscall_64
   entry_SYSCALL_64_after_hwframe
   </TASK>

[CAUSE]
btrfs_balance() expects insert_balance_item() to return -EEXIST only
when a balance item is on disk, and a balance item to be on disk only
when fs_info->balance_ctl is set (a paused balance, or one recovered
at mount). So for a new balance it uses BUG_ON(ret == -EEXIST).

Both assumptions can be wrong:

- insert_balance_item() inserts the item, then commits the transaction.
  btrfs_commit_transaction() can fail without aborting the
  transaction, for example when btrfs_start_dirty_block_groups() fails
  to allocate a path. Then balance fails with -ENOMEM and
  balance_ctl is freed, but the item stays in the running transaction.
  The next balance ioctl finds the item and gets -EEXIST.

- When the transaction was aborted with -EEXIST, for example after
  "failed to run delayed ref ... -17" on a corrupted extent tree,
  btrfs_commit_transaction() returns the abort error, -EEXIST, and
  there is no balance item at all.

[FIX]
Mount turns any balance item on disk into a paused balance, so a new
balance can only find an item left by a balance of the same mount that
failed after inserting it.  No balance owns that item, so let a new
balance overwrite it, run, and delete it at the end as usual, as Filipe
suggested in [1].

For a resumed balance -EEXIST is the normal result.  Any other error,
including the -EEXIST of an aborted transaction for a new balance, now
goes to the existing error path.

The BUG_ON() checks on the return value go away, and the one on
fs_info->balance_ctl becomes an ASSERT().

Reported-by: syzbot+dc9291cf132691aeb478@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=dc9291cf132691aeb478
Link: https://lore.kernel.org/linux-btrfs/ZNzE6CFOzu9kDG+G@debian0.Home/ [1]
Fixes: 1bbc621ef284 ("Btrfs: allow block group cache writeout outside critical section in commit")
Cc: stable@vger.kernel.org # 4.1+
Suggested-by: Filipe Manana <fdmanana@kernel.org>
Signed-off-by: Siddharth Mishra <smish149@asu.edu>
---
 fs/btrfs/volumes.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 3d4ef6725..4a8e5078b 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -3998,6 +3998,8 @@ static int insert_balance_item(struct btrfs_fs_info *fs_info,
 
 	ret = btrfs_insert_empty_item(trans, root, path, &key,
 				      sizeof(*item));
+	if (ret == -EEXIST && !(bctl->flags & BTRFS_BALANCE_RESUME))
+		ret = 0;
 	if (ret)
 		goto out;
 
@@ -5081,17 +5083,17 @@ int btrfs_balance(struct btrfs_fs_info *fs_info,
 	}
 
 	ret = insert_balance_item(fs_info, bctl);
-	if (ret && ret != -EEXIST)
+	if (ret == -EEXIST && (bctl->flags & BTRFS_BALANCE_RESUME))
+		ret = 0;
+	if (ret)
 		goto out;
 
 	if (!(bctl->flags & BTRFS_BALANCE_RESUME)) {
-		BUG_ON(ret == -EEXIST);
-		BUG_ON(fs_info->balance_ctl);
+		ASSERT(!fs_info->balance_ctl);
 		spin_lock(&fs_info->balance_lock);
 		fs_info->balance_ctl = bctl;
 		spin_unlock(&fs_info->balance_lock);
 	} else {
-		BUG_ON(ret != -EEXIST);
 		spin_lock(&fs_info->balance_lock);
 		update_balance_args(bctl);
 		spin_unlock(&fs_info->balance_lock);
-- 
2.54.0


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 2/2] btrfs: tree-checker: add balance item size check
  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 21:47 ` Siddharth Mishra
  2026-11-05 22:06   ` Qu Wenruo
  1 sibling, 1 reply; 7+ messages in thread
From: Siddharth Mishra @ 2026-11-05 21:47 UTC (permalink / raw)
  To: dsterba
  Cc: mason, josef, wqu, fdmanana, linux-btrfs, linux-kernel, Siddharth Mishra

[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


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 2/2] btrfs: tree-checker: add balance item size check
  2026-11-05 21:47 ` [PATCH 2/2] btrfs: tree-checker: add balance item size check Siddharth Mishra
@ 2026-11-05 22:06   ` Qu Wenruo
  0 siblings, 0 replies; 7+ messages in thread
From: Qu Wenruo @ 2026-11-05 22:06 UTC (permalink / raw)
  To: Siddharth Mishra, dsterba
  Cc: mason, josef, fdmanana, linux-btrfs, linux-kernel



在 2026/11/6 08:17, Siddharth Mishra 写道:
> [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.

What's the point? The background provides nothing useful.

You should directly say that a too small balance item can make btrfs to 
read beyond item boundary.

> 
> [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,

Or even beyond the leaf boundary if it's at the last slot, which can be 
more problematic.

> 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

I don't think the succeeded case adds any value.

> 
> [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;
>    +	}
>    +

Don't put another diff part, even with extra spaces to break diff format.

I'm almost hitting the key to send out a comment criticize the 
duplicated code.

All you doing is just to make the whole patch hard to read, not only the 
comments after the "---" but also the cursed alternative.


If you are not sure about what is the correct way to validate such item, 
do read old codes/history of tree-checker and similar patches in the 
mailing list that got rejected.

Then you should not come up with such stupid question of using the 
alternative way.


The patch looks good, but the bad comments after "---" are so bad that 
they make me hesitate to even add my reviewed-by tag.

>     	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:


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 1/2] btrfs: overwrite a leftover balance item instead of BUG_ON()
  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
  0 siblings, 1 reply; 7+ messages in thread
From: Qu Wenruo @ 2026-11-05 22:09 UTC (permalink / raw)
  To: Siddharth Mishra, dsterba
  Cc: mason, josef, fdmanana, linux-btrfs, linux-kernel,
	syzbot+dc9291cf132691aeb478, stable



在 2026/11/6 08:17, Siddharth Mishra 写道:
> [BUG]
> A balance ioctl can hit this BUG_ON():
> 
>    kernel BUG at fs/btrfs/volumes.c:5088!
>    Oops: invalid opcode: 0000 [#1] SMP NOPTI
>    RIP: 0010:btrfs_balance (fs/btrfs/volumes.c:5088)
>    Call Trace:
>     <TASK>
>     btrfs_ioctl (fs/btrfs/ioctl.c:3523 fs/btrfs/ioctl.c:5650)
>     __x64_sys_ioctl
>     do_syscall_64
>     entry_SYSCALL_64_after_hwframe
>     </TASK>
> 
> [CAUSE]
> btrfs_balance() expects insert_balance_item() to return -EEXIST only
> when a balance item is on disk, and a balance item to be on disk only
> when fs_info->balance_ctl is set (a paused balance, or one recovered
> at mount). So for a new balance it uses BUG_ON(ret == -EEXIST).
> 
> Both assumptions can be wrong:
> 
> - insert_balance_item() inserts the item, then commits the transaction.
>    btrfs_commit_transaction() can fail without aborting the
>    transaction, for example when btrfs_start_dirty_block_groups() fails
>    to allocate a path.

I think no call site can handle a btrfs_commit_transaction() failure 
without transaction abort.

This is a way bigger problem than what you're fixing.

> Then balance fails with -ENOMEM and
>    balance_ctl is freed, but the item stays in the running transaction.
>    The next balance ioctl finds the item and gets -EEXIST.
> 
> - When the transaction was aborted with -EEXIST, for example after
>    "failed to run delayed ref ... -17" on a corrupted extent tree,
>    btrfs_commit_transaction() returns the abort error, -EEXIST, and
>    there is no balance item at all.
> 
> [FIX]
> Mount turns any balance item on disk into a paused balance, so a new
> balance can only find an item left by a balance of the same mount that
> failed after inserting it.  No balance owns that item, so let a new
> balance overwrite it, run, and delete it at the end as usual, as Filipe
> suggested in [1].
> 
> For a resumed balance -EEXIST is the normal result.  Any other error,
> including the -EEXIST of an aborted transaction for a new balance, now
> goes to the existing error path.
> 
> The BUG_ON() checks on the return value go away, and the one on
> fs_info->balance_ctl becomes an ASSERT().
> 
> Reported-by: syzbot+dc9291cf132691aeb478@syzkaller.appspotmail.com
> Closes: https://syzkaller.appspot.com/bug?extid=dc9291cf132691aeb478
> Link: https://lore.kernel.org/linux-btrfs/ZNzE6CFOzu9kDG+G@debian0.Home/ [1]
> Fixes: 1bbc621ef284 ("Btrfs: allow block group cache writeout outside critical section in commit")
> Cc: stable@vger.kernel.org # 4.1+
> Suggested-by: Filipe Manana <fdmanana@kernel.org>
> Signed-off-by: Siddharth Mishra <smish149@asu.edu>
> ---
>   fs/btrfs/volumes.c | 10 ++++++----
>   1 file changed, 6 insertions(+), 4 deletions(-)
> 
> diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
> index 3d4ef6725..4a8e5078b 100644
> --- a/fs/btrfs/volumes.c
> +++ b/fs/btrfs/volumes.c
> @@ -3998,6 +3998,8 @@ static int insert_balance_item(struct btrfs_fs_info *fs_info,
>   
>   	ret = btrfs_insert_empty_item(trans, root, path, &key,
>   				      sizeof(*item));
> +	if (ret == -EEXIST && !(bctl->flags & BTRFS_BALANCE_RESUME))
> +		ret = 0;
>   	if (ret)
>   		goto out;
>   
> @@ -5081,17 +5083,17 @@ int btrfs_balance(struct btrfs_fs_info *fs_info,
>   	}
>   
>   	ret = insert_balance_item(fs_info, bctl);
> -	if (ret && ret != -EEXIST)
> +	if (ret == -EEXIST && (bctl->flags & BTRFS_BALANCE_RESUME))
> +		ret = 0;
> +	if (ret)
>   		goto out;
>   
>   	if (!(bctl->flags & BTRFS_BALANCE_RESUME)) {
> -		BUG_ON(ret == -EEXIST);
> -		BUG_ON(fs_info->balance_ctl);
> +		ASSERT(!fs_info->balance_ctl);
>   		spin_lock(&fs_info->balance_lock);
>   		fs_info->balance_ctl = bctl;
>   		spin_unlock(&fs_info->balance_lock);
>   	} else {
> -		BUG_ON(ret != -EEXIST);
>   		spin_lock(&fs_info->balance_lock);
>   		update_balance_args(bctl);
>   		spin_unlock(&fs_info->balance_lock);


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 1/2] btrfs: overwrite a leftover balance item instead of BUG_ON()
  2026-11-05 22:09   ` Qu Wenruo
@ 2026-11-05 22:40     ` Siddharth Mishra
  2026-11-05 22:43       ` Qu Wenruo
  0 siblings, 1 reply; 7+ messages in thread
From: Siddharth Mishra @ 2026-11-05 22:40 UTC (permalink / raw)
  To: Qu Wenruo
  Cc: dsterba, mason, josef, fdmanana, linux-btrfs, linux-kernel,
	syzbot+dc9291cf132691aeb478, stable

On Fri, Nov 06, 2026 at 08:39:01AM +1030, Qu Wenruo wrote:
> >
> > Both assumptions can be wrong:
> >
> > - insert_balance_item() inserts the item, then commits the transaction.
> >    btrfs_commit_transaction() can fail without aborting the
> >    transaction, for example when btrfs_start_dirty_block_groups() fails
> >    to allocate a path.
>
> I think no call site can handle a btrfs_commit_transaction() failure
> without transaction abort.
>
> This is a way bigger problem than what you're fixing.

Are you suggesting that the right fix is to make
btrfs_commit_transaction() abort the transaction when
btrfs_start_dirty_block_groups() fails?

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 1/2] btrfs: overwrite a leftover balance item instead of BUG_ON()
  2026-11-05 22:40     ` Siddharth Mishra
@ 2026-11-05 22:43       ` Qu Wenruo
  0 siblings, 0 replies; 7+ messages in thread
From: Qu Wenruo @ 2026-11-05 22:43 UTC (permalink / raw)
  To: Siddharth Mishra
  Cc: dsterba, mason, josef, fdmanana, linux-btrfs, linux-kernel,
	syzbot+dc9291cf132691aeb478, stable



在 2026/11/6 09:10, Siddharth Mishra 写道:
> On Fri, Nov 06, 2026 at 08:39:01AM +1030, Qu Wenruo wrote:
>>>
>>> Both assumptions can be wrong:
>>>
>>> - insert_balance_item() inserts the item, then commits the transaction.
>>>     btrfs_commit_transaction() can fail without aborting the
>>>     transaction, for example when btrfs_start_dirty_block_groups() fails
>>>     to allocate a path.
>>
>> I think no call site can handle a btrfs_commit_transaction() failure
>> without transaction abort.
>>
>> This is a way bigger problem than what you're fixing.
> 
> Are you suggesting that the right fix is to make
> btrfs_commit_transaction() abort the transaction when
> btrfs_start_dirty_block_groups() fails?

At least one should check if all btrfs_commit_transaction() callers can 
handle such error correctly.

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2026-11-05 22:43 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
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 ` [PATCH 2/2] btrfs: tree-checker: add balance item size check Siddharth Mishra
2026-11-05 22:06   ` Qu Wenruo

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®