From 041340404e110ec70a37538f56d5df3ee72e12c8 Mon Sep 17 00:00:00 2001 From: Vitaliy Kuznetsov Date: Fri, 28 Jul 2023 19:40:14 +0400 Subject: [PATCH] LU-16982 ldiskfs: Fix crash after "umount -d -f /mnt/..." This patch adds an extra state check during the unmount process; Since there was the following problem: Lustre: DEBUG MARKER: umount -d -f /mnt/lustre-mds4 kernel BUG at fs/jbd2/transaction.c:378! CPU: 0 PID: 310834 Comm: kworker/0:2 4.18.0-477.15... Hardware name: Red Hat KVM, BIOS 0.5.1 01/01/2011 Workqueue: events flush_stashed_stats_work [ldiskfs] RIP: 0010:start_this_handle+0x22c/0x520 [jbd2] Call Trace: jbd2__journal_start+0xee/0x1f0 [jbd2] jbd2_journal_start+0x19/0x20 [jbd2] flush_stashed_stats_work+0x36/0x90 [ldiskfs] process_one_work+0x1a7/0x360 worker_thread+0x30/0x390 kthread+0x134/0x150 Fixes: e27a7b33d6 ("LU-16298 ldiskfs: Periodically write ldiskfs superblock") Signed-off-by: Vitaliy Kuznetsov Change-Id: I162d3416ca1fe9bd09f1102ccca892db05719016 Reviewed-on: https://review.whamcloud.com/c/fs/lustre-release/+/51760 Reviewed-by: Andreas Dilger Reviewed-by: Alexander Boyko Reviewed-by: Li Dongyang Reviewed-by: Oleg Drokin Tested-by: jenkins Tested-by: Maloo --- .../ext4-add-periodic-superblock-update.patch | 104 ++++++++++----------- 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/ldiskfs/kernel_patches/patches/rhel8/ext4-add-periodic-superblock-update.patch b/ldiskfs/kernel_patches/patches/rhel8/ext4-add-periodic-superblock-update.patch index bbdad7a..0cf1b6f 100644 --- a/ldiskfs/kernel_patches/patches/rhel8/ext4-add-periodic-superblock-update.patch +++ b/ldiskfs/kernel_patches/patches/rhel8/ext4-add-periodic-superblock-update.patch @@ -17,8 +17,8 @@ periods. Signed-off-by: Vitaliy Kuznetsov --- fs/ext4/ext4.h | 1 + - fs/ext4/super.c | 186 +++++++++++++++++++++++++++++++++++++----------- - 2 files changed, 146 insertions(+), 41 deletions(-) + fs/ext4/super.c | 206 +++++++++++++++++++++++++++++++++++++----------- + 2 files changed, 163 insertions(+), 44 deletions(-) diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 7c7123f265c2..44f69f5c6931 100644 @@ -33,7 +33,7 @@ index 7c7123f265c2..44f69f5c6931 100644 /* the size of zero-out chunk */ unsigned int s_extent_max_zeroout_kb; diff --git a/fs/ext4/super.c b/fs/ext4/super.c -index 10c45b3b7910..9d6e8b48f775 100644 +index 766f2ef08ec1..824cebe50829 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -64,6 +64,7 @@ static struct ratelimit_state ext4_mount_msg_ratelimit; @@ -44,7 +44,7 @@ index 10c45b3b7910..9d6e8b48f775 100644 static int ext4_commit_super(struct super_block *sb, int sync); static void ext4_mark_recovery_complete(struct super_block *sb, struct ext4_super_block *es); -@@ -469,6 +470,90 @@ static int block_device_ejected(struct super_block *sb) +@@ -469,6 +470,93 @@ static int block_device_ejected(struct super_block *sb) return bdi->dev == NULL; } @@ -54,6 +54,7 @@ index 10c45b3b7910..9d6e8b48f775 100644 + s_stats_work); + journal_t *journal = sbi->s_journal; + struct buffer_head *sbh = sbi->s_sbh; ++ struct super_block *sb = sbi->s_sb; + handle_t *handle; + + /* @@ -61,7 +62,8 @@ index 10c45b3b7910..9d6e8b48f775 100644 + * through the journal to avoid collisions of other journalled sb + * updates. + */ -+ if (sb_rdonly(sbi->s_sb) && !journal) ++ if (sb_rdonly(sbi->s_sb) || !(sb->s_flags & SB_ACTIVE) || ++ !journal || (journal->j_flags & JBD2_UNMOUNT)) + return; + + handle = jbd2_journal_start(journal, 1); @@ -76,7 +78,6 @@ index 10c45b3b7910..9d6e8b48f775 100644 + ext4_update_super(sbi->s_sb, 1); + jbd2_journal_dirty_metadata(handle, sbh); + jbd2_journal_stop(handle); -+ return; +} + +#define EXT4_SB_REFRESH_INTERVAL_SEC (3600) /* seconds (1 hour) */ @@ -98,12 +99,14 @@ index 10c45b3b7910..9d6e8b48f775 100644 +{ + struct ext4_sb_info *sbi = EXT4_SB(sb); + struct ext4_super_block *es = sbi->s_es; ++ journal_t *journal = sbi->s_journal; + time64_t now; + __u64 last_update; + __u64 lifetime_write_kbytes; + __u64 diff_size; + -+ if (sb_rdonly(sb)) ++ if (sb_rdonly(sb) || !(sb->s_flags & SB_ACTIVE) || ++ !journal || (journal->j_flags & JBD2_UNMOUNT)) + return; + + now = ktime_get_real_seconds(); @@ -135,24 +138,46 @@ index 10c45b3b7910..9d6e8b48f775 100644 static void ext4_journal_commit_callback(journal_t *journal, transaction_t *txn) { struct super_block *sb = journal->j_private; -@@ -479,7 +564,7 @@ static void ext4_journal_commit_callback(journal_t *journal, transaction_t *txn) - BUG_ON(txn->t_state == T_FINISHED); +@@ -480,6 +568,7 @@ static void ext4_journal_commit_callback(journal_t *journal, transaction_t *txn) ext4_process_freed_data(sb, txn->t_tid); -- + + ext4_maybe_update_superblock(sb); spin_lock(&sbi->s_md_lock); while (!list_empty(&txn->t_private_list)) { jce = list_entry(txn->t_private_list.next, -@@ -1023,6 +1108,7 @@ static void ext4_put_super(struct super_block *sb) +@@ -1021,19 +1110,24 @@ static void ext4_put_super(struct super_block *sb) + int aborted = 0; + int i, err; - ext4_unregister_li_request(sb); - ext4_quota_off_umount(sb); -+ flush_work(&sbi->s_stats_work); - - destroy_workqueue(sbi->rsv_conversion_wq); +- ext4_unregister_li_request(sb); +- flush_workqueue(sbi->s_misc_wq); +- ext4_quota_off_umount(sb); +- +- destroy_workqueue(sbi->s_misc_wq); +- + /* + * Unregister sysfs before destroying jbd2 journal. + * Since we could still access attr_journal_task attribute via sysfs + * path which could have sbi->s_journal->j_task as NULL ++ * Unregister sysfs before flush sbi->s_stats_work. ++ * Since user may read /proc/fs/ext4/xx/mb_groups during umount, If ++ * read metadata verify failed then will queue error work. ++ * flush_stashed_error_work will call start_this_handle may trigger ++ * BUG_ON. + */ + ext4_unregister_sysfs(sb); -@@ -4373,6 +4459,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) ++ ext4_unregister_li_request(sb); ++ flush_workqueue(sbi->s_misc_wq); ++ ext4_quota_off_umount(sb); ++ flush_work(&sbi->s_stats_work); ++ destroy_workqueue(sbi->s_misc_wq); ++ + if (sbi->s_journal) { + aborted = is_journal_aborted(sbi->s_journal); + err = jbd2_journal_destroy(sbi->s_journal); +@@ -4374,6 +4468,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) } timer_setup(&sbi->s_err_report, print_daily_error_info, 0); @@ -160,7 +185,7 @@ index 10c45b3b7910..9d6e8b48f775 100644 /* Register extent status tree shrinker */ if (ext4_es_register_shrinker(sbi)) -@@ -4985,6 +5072,53 @@ static journal_t *ext4_get_dev_journal(struct super_block *sb, +@@ -4986,6 +5081,55 @@ static journal_t *ext4_get_dev_journal(struct super_block *sb, return NULL; } @@ -168,6 +193,7 @@ index 10c45b3b7910..9d6e8b48f775 100644 +{ + struct ext4_super_block *es = EXT4_SB(sb)->s_es; + struct buffer_head *sbh = EXT4_SB(sb)->s_sbh; ++ + if (sync) + lock_buffer(sbh); + @@ -207,6 +233,7 @@ index 10c45b3b7910..9d6e8b48f775 100644 + &EXT4_SB(sb)->s_freeinodes_counter)); + } + ++ ext4_superblock_csum_set(sb); + if (sync) + unlock_buffer(sbh); +} @@ -214,7 +241,7 @@ index 10c45b3b7910..9d6e8b48f775 100644 static int ext4_load_journal(struct super_block *sb, struct ext4_super_block *es, unsigned long journal_devnum) -@@ -5095,7 +5229,6 @@ static int ext4_load_journal(struct super_block *sb, +@@ -5096,7 +5239,6 @@ static int ext4_load_journal(struct super_block *sb, static int ext4_commit_super(struct super_block *sb, int sync) { @@ -222,7 +249,7 @@ index 10c45b3b7910..9d6e8b48f775 100644 struct buffer_head *sbh = EXT4_SB(sb)->s_sbh; int error = 0; -@@ -5109,41 +5242,9 @@ static int ext4_commit_super(struct super_block *sb, int sync) +@@ -5110,39 +5252,10 @@ static int ext4_commit_super(struct super_block *sb, int sync) * device was hot-removed. Not much we can do but fail the I/O. */ if (!buffer_mapped(sbh)) @@ -258,40 +285,13 @@ index 10c45b3b7910..9d6e8b48f775 100644 - es->s_free_inodes_count = - cpu_to_le32(percpu_counter_sum_positive( - &EXT4_SB(sb)->s_freeinodes_counter)); -- BUFFER_TRACE(sbh, "marking dirty"); -- ext4_superblock_csum_set(sb); -- if (sync) -- lock_buffer(sbh); + ext4_update_super(sb, sync); + BUFFER_TRACE(sbh, "marking dirty"); +- ext4_superblock_csum_set(sb); + if (sync) + lock_buffer(sbh); if (buffer_write_io_error(sbh) || !buffer_uptodate(sbh)) { - /* - * Oh, dear. A previous attempt to write the -@@ -5153,19 +5254,19 @@ static int ext4_commit_super(struct super_block *sb, int sync) - * be remapped. Nothing we can do but to retry the - * write and hope for the best. - */ -- ext4_msg(sb, KERN_ERR, "previous I/O error to " -- "superblock detected"); -+ ext4_msg(sb, KERN_ERR, -+ "previous I/O error to superblock detected"); - clear_buffer_write_io_error(sbh); - set_buffer_uptodate(sbh); - } -+ BUFFER_TRACE(sbh, "marking dirty"); - mark_buffer_dirty(sbh); - if (sync) { -- unlock_buffer(sbh); - error = __sync_dirty_buffer(sbh, - REQ_SYNC | (test_opt(sb, BARRIER) ? REQ_FUA : 0)); - if (buffer_write_io_error(sbh)) { -- ext4_msg(sb, KERN_ERR, "I/O error while writing " -- "superblock"); -+ ext4_msg(sb, KERN_ERR, -+ "I/O error while writing superblock"); - clear_buffer_write_io_error(sbh); - set_buffer_uptodate(sbh); - } -@@ -5483,6 +5584,9 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data) +@@ -5484,6 +5599,9 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data) set_task_ioprio(sbi->s_journal->j_task, journal_ioprio); } -- 1.8.3.1