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))) {
                err = z_erofs_scan_folio(&f, folio, true);
                if (err && err != -EINTR)
                        erofs_err(realinode->i_sb, "readahead error at folio 
%lu @ nid %llu",
diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h
index 4e8b2b29f6d3e..90904a4d173b7 100644
--- a/include/linux/pagemap.h
+++ b/include/linux/pagemap.h
@@ -1549,6 +1549,37 @@ static inline struct folio *readahead_folio(struct 
readahead_control *ractl)
        return folio;
 }
 
+/**
+ * readahead_folio_reverse - Get the next folio to read, from the tail.
+ * @ractl: The current readahead request.
+ *
+ * Like readahead_folio(), but walks the range back-to-front. The folio is
+ * returned locked with its refcount dropped; the caller unlocks it once I/O
+ * completes. Compound folios are returned once, at their head index.
+ *
+ * Context: The folio is locked.
+ * Return: A pointer to the next folio, or %NULL when done.
+ */
+static inline struct folio *readahead_folio_reverse(struct readahead_control 
*ractl)
+{
+       struct folio *folio;
+
+       if (!ractl->_nr_pages)
+               return NULL;
+
+       /* xa_load() follows sibling entries, so a tail index returns the head 
*/
+       folio = xa_load(&ractl->mapping->i_pages,
+                       ractl->_index + ractl->_nr_pages - 1);
+       VM_WARN_ON_ONCE_FOLIO(!folio_test_locked(folio), folio);
+
+       /* Shrink the window from the tail down to this folio's head index */
+       ractl->_nr_pages = folio->index - ractl->_index;
+       ractl->_batch_count = 0;
+
+       folio_put(folio);
+       return folio;
+}
+
 static inline unsigned int __readahead_batch(struct readahead_control *rac,
                struct page **array, unsigned int array_sz)
 {

-- 
2.53.0


Reply via email to