| From: Chi Zhiling <chizhiling@kylinos.cn> |
| Subject: mpage: terminate read-ahead on read error |
| Date: Fri, 29 Aug 2025 10:36:58 +0800 |
| |
| For exFAT filesystems with 4MB read_ahead_size, removing the storage |
| device during read operations can delay EIO error reporting by several |
| minutes. This occurs because the read-ahead implementation in mpage |
| doesn't handle errors. |
| |
| Another reason for the delay is that the filesystem requires metadata to |
| issue file read request. When the storage device is removed, the metadata |
| buffers are invalidated, causing mpage to repeatedly attempt to fetch |
| metadata during each get_block call. |
| |
| The original purpose of this patch is terminate read ahead when we fail to |
| get metadata, to make the patch more generic, implement it by checking |
| folio status, instead of checking the return of get_block(). |
| |
| So, if a folio is synchronously unlocked and non-uptodate, should we quit |
| the read ahead? |
| |
| I think it depends on whether the error is permanent or temporary, and |
| whether further read ahead might succeed. A device being unplugged is one |
| reason for returning such a folio, but we could return it for many other |
| reasons (e.g., metadata errors). I think most errors won't be restored in |
| a short time, so we should quit read ahead when they occur. |
| |
| Link: https://lkml.kernel.org/r/20250829023659.688649-1-chizhiling@163.com |
| Signed-off-by: Chi Zhiling <chizhiling@kylinos.cn> |
| Reviewed-by: Jan Kara <jack@suse.cz> |
| Cc: Al Viro <viro@zeniv.linux.org.uk> |
| Cc: Christian Brauner <brauner@kernel.org> |
| Cc: Matthew Wilcox (Oracle) <willy@infradead.org> |
| Cc: Namjae Jeon <linkinjeon@kernel.org> |
| Cc: Sungjong Seo <sj1557.seo@samsung.com> |
| Cc: Yuezhang Mo <Yuezhang.Mo@sony.com> |
| Signed-off-by: Andrew Morton <akpm@linux-foundation.org> |
| --- |
| |
| fs/mpage.c | 6 ++++++ |
| 1 file changed, 6 insertions(+) |
| |
| --- a/fs/mpage.c~mpage-terminate-read-ahead-on-read-error |
| +++ a/fs/mpage.c |
| @@ -369,6 +369,12 @@ void mpage_readahead(struct readahead_co |
| args.folio = folio; |
| args.nr_pages = readahead_count(rac); |
| args.bio = do_mpage_readpage(&args); |
| + /* |
| + * If read ahead failed synchronously, it may cause by removed |
| + * device, or some filesystem metadata error. |
| + */ |
| + if (!folio_test_locked(folio) && !folio_test_uptodate(folio)) |
| + break; |
| } |
| if (args.bio) |
| mpage_bio_submit_read(args.bio); |
| _ |