[PATCH] ext4: do not WARN when starting a journal on a frozen filesystem

From: Luyao Bai

Date: Thu Jul 23 2026 - 16:51:40 EST


A WARNING is triggered in ext4_journal_check_start() when a background
writeback thread attempts to start a journal transaction while the
filesystem is in the SB_FREEZE_COMPLETE state:

WARNING: CPU: 1 PID: 2903 at fs/ext4/ext4_jbd2.c:76
ext4_journal_check_start+0x1f8/0x250
Call Trace:
__ext4_journal_start_sb+0x181/0x600 fs/ext4/ext4_jbd2.c:105
__ext4_journal_start fs/ext4/ext4_jbd2.h:326 [inline]
ext4_do_writepages+0x112c/0x3d20 fs/ext4/inode.c:2707
ext4_writepages+0x213/0x3c0 fs/ext4/inode.c:2813
do_writepages+0x35f/0x870 mm/page-writeback.c:2683
__writeback_single_inode+0x14f/0x10d0 fs/fs-writeback.c:1658
writeback_sb_inodes+0x80c/0x1370 fs/fs-writeback.c:1954
wb_writeback+0x41b/0xbd0 fs/fs-writeback.c:2134
wb_workfn+0x410/0x1090 fs/fs-writeback.c:2321

The background writeback flusher does not take freeze protection, so it
can legitimately reach ext4_do_writepages() and try to start a journal
handle while the filesystem is frozen. This happens, for example, when
ext4_writepages() failed earlier (e.g. -ENOSPC or -EDQUOT) during the
sync_filesystem() phase of the freeze: sync_filesystem() can still
return 0, the freeze completes, but dirty pages are left behind. A later
writeback pass then tries to write them out on the now-frozen
filesystem.

The same state is reachable through the EXT4_IOC_SHUTDOWN path: if
fs_bdev_freeze() succeeds in freezing the superblock but the subsequent
sync_blockdev() fails, the filesystem is left in SB_FREEZE_COMPLETE and
dirty pages remain, so writeback eventually retries and trips the WARN.

Because this state can be reached without any kernel bug, WARN_ON() is
the wrong tool here: WARN_ON() must only fire on conditions that should
never happen. Replace it with an ext4_msg() error message and return
-EROFS, rejecting the transaction cleanly. All callers of
__ext4_journal_start_sb() already handle an error return (it is the same
path used for the existing is_journal_aborted() -EROFS case), so the
dirty pages are simply kept and written back once the filesystem is
thawed.

This patch is intentionally limited to the ext4 journal-start check,
which is the direct cause of the reported warning. Any improvements to
the generic VFS freeze/thaw error handling in fs/super.c are a separate
concern and are deliberately left out of this fix.

Reported-by: syzbot+b75d75f957975f3d40e3@xxxxxxxxxxxxxxxxxxxxxxxxx
Closes: https://syzkaller.appspot.com/bug?extid=b75d75f957975f3d40e3
Fixes: 49ef8832fb1a ("bdev: implement freeze and thaw holder operations")
Signed-off-by: Luyao Bai <bailuyao1997@xxxxxxxxx>
---
Tested with the syzbot reproducer under QEMU: the WARNING at
fs/ext4/ext4_jbd2.c fires on a clean mainline build and no longer fires
with this patch applied.

fs/ext4/ext4_jbd2.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/fs/ext4/ext4_jbd2.c b/fs/ext4/ext4_jbd2.c
index 9a8c225f2..1756039b1 100644
--- a/fs/ext4/ext4_jbd2.c
+++ b/fs/ext4/ext4_jbd2.c
@@ -75,7 +75,12 @@ static int ext4_journal_check_start(struct super_block *sb)
if (WARN_ON_ONCE(sb_rdonly(sb)))
return -EROFS;

- WARN_ON(sb->s_writers.frozen == SB_FREEZE_COMPLETE);
+ if (unlikely(sb->s_writers.frozen == SB_FREEZE_COMPLETE)) {
+ ext4_msg(sb, KERN_ERR,
+ "Attempt to start a journal transaction on a frozen filesystem");
+ return -EROFS;
+ }
+
journal = EXT4_SB(sb)->s_journal;
/*
* Special case here: if the journal has aborted behind our
--
2.43.0