ext4: Avoid entering writeback paths during fastcommit replay

Fastcommit replay effectively happens in nojournal mode. This results in
ext4_mark_iloc_dirty() setting I_METADATA_WRITEBACK flag and as a result
we end up entering filesystem writeback functions. However during
fastcommit replay s_writepages_rwsem isn't initialized yet and hence we
crash.

Fix the problem by avoiding setting I_METADATA_WRITEBACK during
fastcommit replay. Journal replay flushes the whole block device after
replay anyway so all metadata is properly persisted and replay is faster
this way as a bonus.

Fixes: c26339e1df ("ext4: Fix data integrity writeout issues in nojournal mode")
Reported-by: Venkat Rao Bagalkote <venkat88@linux.ibm.com>
Reported-by: Ojaswin Mujoo <ojaswin@linux.ibm.com>
Signed-off-by: Jan Kara <jack@suse.cz>
Link: https://patch.msgid.link/20260804104112.93202-2-jack@suse.cz
Tested-by: Venkat Rao Bagalkote <venkat88@linux.ibm.com>
Reviewed-by: Ojaswin Mujoo <ojaswin@linux.ibm.com>
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
This commit is contained in:
Jan Kara 2026-08-04 12:41:13 +02:00 committed by Christian Brauner
parent 818bebeb63
commit 0ecd56573c
No known key found for this signature in database
GPG Key ID: 91C61BC06578DCA2

View File

@ -6456,9 +6456,10 @@ int ext4_chunk_trans_blocks(struct inode *inode, int nrblocks)
int ext4_mark_iloc_dirty(handle_t *handle,
struct inode *inode, struct ext4_iloc *iloc)
{
struct super_block *sb = inode->i_sb;
int err = 0;
err = ext4_emergency_state(inode->i_sb);
err = ext4_emergency_state(sb);
if (unlikely(err)) {
put_bh(iloc->bh);
return err;
@ -6473,9 +6474,13 @@ int ext4_mark_iloc_dirty(handle_t *handle,
put_bh(iloc->bh);
/*
* Mark that there's metadata writeout pending for the inode so that it
* gets properly flushed on fsync(2) and similar.
* gets properly flushed on fsync(2) and similar. We don't bother for
* fastcommit replay as that flushes the whole bdev afterwards anyway.
* It is faster this way and we avoid entering fs writeback paths which
* aren't fully initialized yet.
*/
if (!EXT4_SB(inode->i_sb)->s_journal) {
if (!ext4_handle_valid(handle) &&
!(EXT4_SB(sb)->s_mount_state & EXT4_FC_REPLAY)) {
/*
* Inode didn't need to go through dirtying, make sure it is
* attached to wb so that writeback can handle it.