From: yangerkun yangerkun@huawei.com
hulk inclusion category: bugfix bugzilla: 172146 CVE: NA ---------------------------
'commit c92dc856848f ("ext4: defer saving error info from atomic context")' and '2d01ddc86606 ("ext4: save error info to sb through journal if available")' add s_error_work to fix checksum error problem. But the error path in ext4_fill_super can lead the follow BUG_ON.
Our testcase got follow BUG: [32031.759805] ------------[ cut here ]------------ [32031.759807] kernel BUG at fs/jbd2/transaction.c:373! [32031.760075] invalid opcode: 0000 [#1] SMP PTI [32031.760336] CPU: 5 PID: 1029268 Comm: kworker/5:1 Kdump: loaded Tainted: G OE --------- - - 4.18.0 ... [32031.766665] jbd2__journal_start+0xf1/0x1f0 [jbd2] [32031.766934] jbd2_journal_start+0x19/0x20 [jbd2] [32031.767218] flush_stashed_error_work+0x30/0x90 [ext4] [32031.767487] process_one_work+0x195/0x390 [32031.767747] worker_thread+0x30/0x390 [32031.768007] ? process_one_work+0x390/0x390 [32031.768265] kthread+0x10d/0x130 [32031.768521] ? kthread_flush_work_fn+0x10/0x10 [32031.768778] ret_from_fork+0x35/0x40
static int start_this_handle(...) BUG_ON(journal->j_flags & JBD2_UNMOUNT); <---- Trigger this
flush_stashed_error_work will try to access journal. We cannot flush s_error_work after journal destroy.
Fixes: c92dc856848f ("ext4: defer saving error info from atomic context") Fixes: 2d01ddc86606 ("ext4: save error info to sb through journal if available") Signed-off-by: yangerkun yangerkun@huawei.com Reviewed-by: Zhang Yi yi.zhang@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- fs/ext4/super.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/fs/ext4/super.c b/fs/ext4/super.c index d793e597c0623..0783f85a1c6cc 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -4831,14 +4831,15 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) ext4_xattr_destroy_cache(sbi->s_ea_block_cache); sbi->s_ea_block_cache = NULL; } - if (sbi->s_journal) { - jbd2_journal_destroy(sbi->s_journal); - sbi->s_journal = NULL; - } failed_mount3a: ext4_es_unregister_shrinker(sbi); failed_mount3: flush_work(&sbi->s_error_work); + + if (sbi->s_journal) { + jbd2_journal_destroy(sbi->s_journal); + sbi->s_journal = NULL; + } del_timer_sync(&sbi->s_err_report); ext4_stop_mmpd(sbi); failed_mount2: