Re: [PATCH RFC 07/14] fs/erofs: mm/pagemap: add readahead_folio_reverse() to avoid folio->private
From: Gao Xiang
Date: Mon Aug 03 2026 - 19:56:19 EST
On Fri, Jul 31, 2026 at 10:13:30PM -0400, Zi Yan wrote:
> erofs needs to traverse readahead folios in reverse order to achieve
> maximum performance by
> 1. reading all folios from readahead_folio();
> 2. storing the prior folio pointer in folio->private;
> 3. traverse from the last folio to the first one.
>
> Add readahead_folio_reverse() to achieve the same function without using
> folio->private.
>
> It prepares for a future commit that replaces PG_private checks with
> !folio->private checks. After switching the checks, erofs's use of
> folio->private without bumping folio refcount can cause unexpected
> outcomes, e.g., in filemap_release_folio(), try_to_free_buffers() becomes
> reachable.
>
> No funtional change intended.
>
> Assisted-by: Claude:claude-opus-4-8
> Assisted-by: Codex:gpt-5
> Signed-off-by: Zi Yan <ziy@xxxxxxxxxx>
> To: Gao Xiang <xiang@xxxxxxxxxx>
> To: Chao Yu <chao@xxxxxxxxxx>
> To: "Matthew Wilcox (Oracle)" <willy@xxxxxxxxxxxxx>
> To: Jan Kara <jack@xxxxxxx>
> Cc: Yue Hu <zbestahu@xxxxxxxxx>
> Cc: Jeffle Xu <jefflexu@xxxxxxxxxxxxxxxxx>
> Cc: Sandeep Dhavale <dhavale@xxxxxxxxxx>
> Cc: Hongbo Li <hongbohbli@xxxxxxxxxxx>
> Cc: Chunhai Guo <guochunhai@xxxxxxxx>
> Cc: linux-erofs@xxxxxxxxxxxxxxxx
> Cc: linux-kernel@xxxxxxxxxxxxxxx
> Cc: linux-fsdevel@xxxxxxxxxxxxxxx
> Cc: linux-mm@xxxxxxxxx
> ---
> fs/erofs/zdata.c | 11 ++---------
> include/linux/pagemap.h | 31 +++++++++++++++++++++++++++++++
> 2 files changed, 33 insertions(+), 9 deletions(-)
>
> diff --git a/fs/erofs/zdata.c b/fs/erofs/zdata.c
> index 74520e9102596..b59f2745a8e72 100644
> --- a/fs/erofs/zdata.c
> +++ b/fs/erofs/zdata.c
> @@ -1902,21 +1902,14 @@ static void z_erofs_readahead(struct readahead_control *rac)
> struct inode *realinode = erofs_real_inode(sharedinode, &need_iput);
> Z_EROFS_DEFINE_FRONTEND(f, realinode, sharedinode, readahead_pos(rac));
> unsigned int nrpages = readahead_count(rac);
> - struct folio *head = NULL, *folio;
> + struct folio *folio;
> int err;
>
> trace_erofs_readahead(realinode, readahead_index(rac), nrpages, false);
> z_erofs_pcluster_readmore(&f, rac, true);
> - while ((folio = readahead_folio(rac))) {
> - folio->private = head;
> - head = folio;
> - }
>
> /* traverse in reverse order for best metadata I/O performance */
> - while (head) {
> - folio = head;
> - head = folio_get_private(folio);
> -
> + while ((folio = readahead_folio_reverse(rac))) {
Yes, it's needed due to EROFS compression metadata design and on-demand
partial decompression, the last extent in the readahead request can be
parsed as a partial extent (means from the starting logical offset of
extents to the necessary offset.). Since there may be many extents
in a single readahead request, so it needs to iterate backwards here;
but the actual compressed data I/Os will be issued forwards.
Previously I tend to avoid touching core-mm so it uses folio->private
but if MM folks can provide a new helper, that would be very helpful
(one more words: all folios are locked in the forward order previously,
so it won't have any deadlock risk).
Thanks,
Gao Xiang