ext4_fc_replay_cleanup() is only ever called on the success path of __ext4_fill_super(). Fast commit replay runs from jbd2_journal_load(), so a mount that fails after that point leaks the fc_regions and fc_modified_inodes allocated during replay. Call ext4_fc_replay_cleanup() from the failed_mount3a error path, which every failure after jbd2_journal_load() goes through. Do it after draining deferred EA inode iputs, so evictions still run with EXT4_FC_REPLAY set. On paths where no replay happened both are NULL so this would be a no-op. Failures after the success path ext4_fc_replay_cleanup() call fall through failed_mount3a as well, so set both pointers to NULL after freeing them to avoid a double free. Fixes: 8016e29f4362 ("ext4: fast commit recovery path") Signed-off-by: Lukas Czerner --- fs/ext4/fast_commit.c | 2 ++ fs/ext4/super.c | 1 + 2 files changed, 3 insertions(+) diff --git a/fs/ext4/fast_commit.c b/fs/ext4/fast_commit.c index 0cac890cf370..e8917bce67af 100644 --- a/fs/ext4/fast_commit.c +++ b/fs/ext4/fast_commit.c @@ -2397,7 +2397,9 @@ void ext4_fc_replay_cleanup(struct super_block *sb) sbi->s_mount_state &= ~EXT4_FC_REPLAY; kfree(sbi->s_fc_replay_state.fc_regions); + sbi->s_fc_replay_state.fc_regions = NULL; kfree(sbi->s_fc_replay_state.fc_modified_inodes); + sbi->s_fc_replay_state.fc_modified_inodes = NULL; } static bool ext4_fc_value_len_isvalid(struct ext4_sb_info *sbi, diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 3ace06b4f9e3..d368b87a537a 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -5813,6 +5813,7 @@ failed_mount8: __maybe_unused failed_mount3a: /* Drain deferred EA inode iputs from journal replay */ flush_delayed_work(&sbi->s_ea_inode_work); + ext4_fc_replay_cleanup(sb); ext4_es_unregister_shrinker(sbi); ext4_es_destroy_stats(sbi); failed_mount3: -- 2.56.0