From: Wenjie Qi Date: Thu, 21 May 2026 10:37:48 +0000 (+0800) Subject: f2fs: avoid false shutdown fserror reports X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=484c84ecc1a497d09239ca3a12dff3cc832830ce;p=thirdparty%2Flinux.git f2fs: avoid false shutdown fserror reports F2FS records image errors and checkpoint-stop reasons through the same s_error_work worker. The ordinary f2fs_handle_error() path only updates s_errors, but the worker still calls fserror_report_shutdown() unconditionally after committing the superblock. As a result, a metadata corruption report can be followed by a synthetic FAN_FS_ERROR event with ESHUTDOWN and an invalid superblock file handle, even though no stop reason was recorded. Track whether save_stop_reason() actually changed the stop_reason array and only report the shutdown fserror for that case. Pure s_errors updates still commit the superblock, but no longer generate a false shutdown event. Fixes: 50faed607d32 ("f2fs: support to report fserror") Cc: stable@kernel.org Reviewed-by: Chao Yu Signed-off-by: Wenjie Qi Signed-off-by: Jaegeuk Kim --- diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index b83ff4bd96ec6..9f24287de4c31 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -1989,6 +1989,7 @@ struct f2fs_sb_info { unsigned char stop_reason[MAX_STOP_REASON]; /* stop reason */ spinlock_t error_lock; /* protect errors/stop_reason array */ bool error_dirty; /* errors of sb is dirty */ + bool stop_reason_dirty; /* stop reason of sb is dirty */ /* For reclaimed segs statistics per each GC mode */ unsigned int gc_segment_mode; /* GC state for reclaimed segments */ diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 629548d78db04..b277807c81850 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -4626,6 +4626,7 @@ static void save_stop_reason(struct f2fs_sb_info *sbi, unsigned char reason) spin_lock_irqsave(&sbi->error_lock, flags); if (sbi->stop_reason[reason] < GENMASK(BITS_PER_BYTE - 1, 0)) sbi->stop_reason[reason]++; + sbi->stop_reason_dirty = true; spin_unlock_irqrestore(&sbi->error_lock, flags); } @@ -4633,6 +4634,7 @@ static void f2fs_record_stop_reason(struct f2fs_sb_info *sbi) { struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi); unsigned long flags; + bool report_shutdown = false; int err; f2fs_down_write(&sbi->sb_lock); @@ -4644,6 +4646,10 @@ static void f2fs_record_stop_reason(struct f2fs_sb_info *sbi) sbi->error_dirty = false; } memcpy(raw_super->s_stop_reason, sbi->stop_reason, MAX_STOP_REASON); + if (sbi->stop_reason_dirty) { + report_shutdown = true; + sbi->stop_reason_dirty = false; + } spin_unlock_irqrestore(&sbi->error_lock, flags); err = f2fs_commit_super(sbi, false); @@ -4654,7 +4660,8 @@ static void f2fs_record_stop_reason(struct f2fs_sb_info *sbi) "f2fs_commit_super fails to record stop_reason, err:%d", err); - fserror_report_shutdown(sbi->sb, GFP_NOFS); + if (report_shutdown) + fserror_report_shutdown(sbi->sb, GFP_NOFS); } void f2fs_save_errors(struct f2fs_sb_info *sbi, unsigned char flag)