[PATCH RFC] btrfs: abort transaction directly on errors in commit path
"syzbot" <[email protected]> Thu, 9 Jul 2026 19:08:55 +0000 (UTC)
| Newsgroups | dev.linux.lists.syzbot |
|---|---|
| Message-ID | <[email protected]> |
When a transaction commit fails due to filesystem corruption (-EUCLEAN),
some functions like btrfs_qgroup_account_extents() and btrfs_update_root()
return the error without explicitly calling btrfs_abort_transaction(). This
forces the generic cleanup_transaction() fallback to abort the transaction,
which masks the actual location of the failure in the stack trace.
This results in confusing warnings that do not point to the actual failure:
BTRFS warning (device loop0): Skipping commit of aborted transaction.
[ cut here ]
btrfs_abort_should_print_stack(__error)
WARNING: fs/btrfs/transaction.c:2068 at cleanup_transaction+0x727/0x7c0
...
Call Trace:
<TASK>
btrfs_commit_transaction+0x262c/0x30b0
prepare_to_relocate+0x3dd/0x4e0
relocate_block_group+0x141/0xe90
do_nonremap_reloc+0xa7/0x560
btrfs_relocate_block_group+0x6e2/0xaf0
btrfs_relocate_chunk+0x114/0x830
__btrfs_balance+0x1b6e/0x29e0
btrfs_balance+0xaa6/0x1180
btrfs_ioctl_balance+0x3dd/0x640
Fix this by calling btrfs_abort_transaction() directly in these functions
when they encounter an error. For btrfs_update_root(), -ENOSPC is a normal
error when updating the log root tree (e.g., during btrfs_sync_log()), so
we only abort if it is not the log root tree or the error is not -ENOSPC.
Additionally, btrfs_abort_transaction() triggers a WARN_ON for -EUCLEAN and
-ENOSPC because they are not in the ignore list of
btrfs_abort_should_print_stack(). WARN_ON must not be used for conditions
that can legitimately happen, such as encountering a corrupted filesystem
image (-EUCLEAN) or running out of space (-ENOSPC). To prevent unnecessary
warnings, add -EUCLEAN and -ENOSPC to the ignore list. To ensure we still
get meaningful stack traces for debugging, add manual dump_stack() calls in
__btrfs_abort_transaction() for these specific errors.
Fixes: 72bd2323ec87 ("Btrfs: do not abort transaction at btrfs_update_root() after failure to COW path")
Assisted-by: Gemini:gemini-3.1-pro-preview Gemini:gemini-3-flash-preview syzbot
Reported-by: [email protected]
Closes: https://syzkaller.appspot.com/bug?extid=021d10c4d4edc87daa03
Link: https://syzkaller.appspot.com/ai_job?id=36e1fafd-13a6-44c6-a988-98fb6981cb2b
To: "Chris Mason" <[email protected]>
To: "David Sterba" <[email protected]>
To: <[email protected]>
To: "Filipe Manana" <[email protected]>
Cc: <[email protected]>
---
diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c
index 502fb4a55..1870595f1 100644
--- a/fs/btrfs/qgroup.c
+++ b/fs/btrfs/qgroup.c
@@ -3068,8 +3068,10 @@ int btrfs_qgroup_account_extents(struct btrfs_trans_handle *trans)
if (!record->old_roots) {
/* Search commit root to find old_roots */
ret = btrfs_find_all_roots(&ctx, false);
- if (ret < 0)
+ if (ret < 0) {
+ btrfs_abort_transaction(trans, ret);
goto cleanup;
+ }
record->old_roots = ctx.roots;
ctx.roots = NULL;
}
@@ -3082,8 +3084,10 @@ int btrfs_qgroup_account_extents(struct btrfs_trans_handle *trans)
ctx.trans = trans;
ctx.time_seq = BTRFS_SEQ_LAST;
ret = btrfs_find_all_roots(&ctx, false);
- if (ret < 0)
+ if (ret < 0) {
+ btrfs_abort_transaction(trans, ret);
goto cleanup;
+ }
new_roots = ctx.roots;
if (qgroup_to_skip) {
ulist_del(new_roots, qgroup_to_skip, 0);
diff --git a/fs/btrfs/root-tree.c b/fs/btrfs/root-tree.c
index 90659b287..13695e4f4 100644
--- a/fs/btrfs/root-tree.c
+++ b/fs/btrfs/root-tree.c
@@ -142,8 +142,17 @@ int btrfs_update_root(struct btrfs_trans_handle *trans, struct btrfs_root
return -ENOMEM;
ret = btrfs_search_slot(trans, root, key, path, 0, 1);
- if (ret < 0)
+ if (ret < 0) {
+ /*
+ * Abort the transaction if we are not updating the log root tree.
+ * In btrfs_sync_log, -ENOSPC is a normal error and should not
+ * abort the transaction.
+ */
+ if (ret != -ENOSPC ||
+ root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID)
+ btrfs_abort_transaction(trans, ret);
return ret;
+ }
if (unlikely(ret > 0)) {
btrfs_crit(fs_info,
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index 8f9419728..aa53eb831 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -2751,8 +2751,16 @@ void __cold __btrfs_abort_transaction(struct btrfs_trans_handle *trans,
if (first_hit) {
btrfs_err(fs_info, "Transaction %llu aborted (error %d)",
trans->transid, error);
- if (error == -ENOSPC)
+ if (error == -ENOSPC) {
btrfs_dump_space_info_for_trans_abort(fs_info);
+ dump_stack();
+ }
+ if (error == -EUCLEAN) {
+ btrfs_err(
+ fs_info,
+ "Aborting transaction due to filesystem corruption");
+ dump_stack();
+ }
}
/* Wake up anybody who may be waiting on this transaction */
wake_up(&fs_info->transaction_wait);
diff --git a/fs/btrfs/transaction.h b/fs/btrfs/transaction.h
index 5e4b1106f..ec66a60cc 100644
--- a/fs/btrfs/transaction.h
+++ b/fs/btrfs/transaction.h
@@ -237,6 +237,8 @@ static inline bool btrfs_abort_should_print_stack(int error)
case -EIO:
case -EROFS:
case -ENOMEM:
+ case -EUCLEAN:
+ case -ENOSPC:
return false;
}
return true;
base-commit: 8cdeaa50eae8dad34885515f62559ee83e7e8dda
--
This is an AI-generated patch subject to moderation.
Reply with '#syz upstream' to Sign-off the patch as a human author
and send it to the upstream kernel mailing lists.
Reply with '#syz reject' to reject it ('#syz unreject' to undo).
See https://goo.gle/syzbot-ai-patches for information about AI-generated patches.
You can comment on the patch as usual, syzbot will try to address
the comments and send a new version of the patch if necessary.
syzbot engineers can be reached at [email protected].