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 <[email protected]>
> To: Gao Xiang <[email protected]>
> To: Chao Yu <[email protected]>
> To: "Matthew Wilcox (Oracle)" <[email protected]>
> To: Jan Kara <[email protected]>
> Cc: Yue Hu <[email protected]>
> Cc: Jeffle Xu <[email protected]>
> Cc: Sandeep Dhavale <[email protected]>
> Cc: Hongbo Li <[email protected]>
> Cc: Chunhai Guo <[email protected]>
> Cc: [email protected]
> Cc: [email protected]
> Cc: [email protected]
> Cc: [email protected]
> ---
>  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

Reply via email to