From: Chi Zhiling chizhiling@kylinos.cn
[ Upstream commit 6dfba108387bf4e71411b3da90b2d5cce48ba054 ]
For exFAT filesystems with 4MB read_ahead_size, removing the storage device when the read operation is in progress, which cause the last read syscall spent 150s [1]. The main reason is that exFAT generates excessive log messages [2].
After applying this patch, approximately 300,000 lines of log messages were suppressed, and the delay of the last read() syscall was reduced to about 4 seconds.
[1]: write(5, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 131072) = 131072 <0.000120> read(4, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 131072) = 131072 <0.000032> write(5, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 131072) = 131072 <0.000119> read(4, 0x7fccf28ae000, 131072) = -1 EIO (Input/output error) <150.186215>
[2]: [ 333.696603] exFAT-fs (vdb): error, failed to access to FAT (entry 0x0000d780, err:-5) [ 333.697378] exFAT-fs (vdb): error, failed to access to FAT (entry 0x0000d780, err:-5) [ 333.698156] exFAT-fs (vdb): error, failed to access to FAT (entry 0x0000d780, err:-5)
Signed-off-by: Chi Zhiling chizhiling@kylinos.cn Signed-off-by: Namjae Jeon linkinjeon@kernel.org Signed-off-by: Sasha Levin sashal@kernel.org ---
LLM Generated explanations, may be completely bogus:
YES. The change switches the hot error sites in `exfat_ent_get()` to the already-available rate-limited logger (`fs/exfat/fatent.c:96`, `:104`, `:112`, `:120`, `:128`), so the driver still returns the same `-EIO` codes but no longer emits hundreds of thousands of synchronous `exfat_fs_error()` messages that were stretching the failing read path to ~150 s. Because `exfat_fs_error_ratelimit()` simply gates the printk while preserving the remount/panic handling in `__exfat_fs_error()` (`fs/exfat/exfat_fs.h:555-561`, `fs/exfat/misc.c:26-47`), correctness isn’t touched. The rate limiter is already initialized per superblock (`fs/exfat/super.c:803-808`) and used in other exFAT paths (`fs/exfat/inode.c:288`), so the patch aligns this high-frequency error path with existing practice. This is a contained fix for a user-visible regression (extreme latency when media disappears), introduces no architectural changes, and applies cleanly to stable trees that already ship the same infrastructure.
fs/exfat/fatent.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/fs/exfat/fatent.c b/fs/exfat/fatent.c index 232cc7f8ab92f..825083634ba2d 100644 --- a/fs/exfat/fatent.c +++ b/fs/exfat/fatent.c @@ -89,35 +89,36 @@ int exfat_ent_get(struct super_block *sb, unsigned int loc, int err;
if (!is_valid_cluster(sbi, loc)) { - exfat_fs_error(sb, "invalid access to FAT (entry 0x%08x)", + exfat_fs_error_ratelimit(sb, + "invalid access to FAT (entry 0x%08x)", loc); return -EIO; }
err = __exfat_ent_get(sb, loc, content); if (err) { - exfat_fs_error(sb, + exfat_fs_error_ratelimit(sb, "failed to access to FAT (entry 0x%08x, err:%d)", loc, err); return err; }
if (*content == EXFAT_FREE_CLUSTER) { - exfat_fs_error(sb, + exfat_fs_error_ratelimit(sb, "invalid access to FAT free cluster (entry 0x%08x)", loc); return -EIO; }
if (*content == EXFAT_BAD_CLUSTER) { - exfat_fs_error(sb, + exfat_fs_error_ratelimit(sb, "invalid access to FAT bad cluster (entry 0x%08x)", loc); return -EIO; }
if (*content != EXFAT_EOF_CLUSTER && !is_valid_cluster(sbi, *content)) { - exfat_fs_error(sb, + exfat_fs_error_ratelimit(sb, "invalid access to FAT (entry 0x%08x) bogus content (0x%08x)", loc, *content); return -EIO;