[PATCH v11 02/36] mm: Make readahead store folio count in readahead_control

From: David Howells

Date: Wed Sep 02 2026 - 13:46:12 EST


Make readahead store folio count in readahead_control so that the
filesystem can know in advance how many folios it needs to keep track of.

This is cleared by read_pages() in case it is called from a loop.

The count is accessed by the filesystem with readahead_folio_count().

Signed-off-by: David Howells <dhowells@xxxxxxxxxx>
cc: Paulo Alcantara (Red Hat) <pc@xxxxxxxxxxxxx>
cc: Matthew Wilcox <willy@xxxxxxxxxxxxx>
cc: netfs@xxxxxxxxxxxxxxx
cc: linux-mm@xxxxxxxxx
cc: linux-fsdevel@xxxxxxxxxxxxxxx
---
include/linux/pagemap.h | 10 ++++++++++
mm/readahead.c | 5 +++++
2 files changed, 15 insertions(+)

diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h
index c6fc783aaee5..e2161bce13dd 100644
--- a/include/linux/pagemap.h
+++ b/include/linux/pagemap.h
@@ -1377,6 +1377,7 @@ struct readahead_control {
struct file_ra_state *ra;
/* private: use the readahead_* accessors instead */
pgoff_t _index;
+ unsigned int _nr_folios;
unsigned int _nr_pages;
unsigned int _batch_count;
bool dropbehind;
@@ -1556,6 +1557,15 @@ static inline size_t readahead_batch_length(const struct readahead_control *rac)
return rac->_batch_count * PAGE_SIZE;
}

+/**
+ * readahead_folio_count - Get the number of folios in this readahead request.
+ * @rac: The readahead request.
+ */
+static inline unsigned int readahead_folio_count(const struct readahead_control *rac)
+{
+ return rac->_nr_folios;
+}
+
static inline unsigned long dir_pages(const struct inode *inode)
{
return (unsigned long)(inode->i_size + PAGE_SIZE - 1) >>
diff --git a/mm/readahead.c b/mm/readahead.c
index 6e5563290287..196542fb1c93 100644
--- a/mm/readahead.c
+++ b/mm/readahead.c
@@ -188,6 +188,7 @@ static void read_pages(struct readahead_control *rac)
if (unlikely(rac->_workingset))
psi_memstall_leave(&rac->_pflags);
rac->_workingset = false;
+ rac->_nr_folios = 0;

BUG_ON(readahead_count(rac));
}
@@ -303,6 +304,7 @@ void page_cache_ra_unbounded(struct readahead_control *ractl,
if (i == mark)
folio_set_readahead(folio);
ractl->_workingset |= folio_test_workingset(folio);
+ ractl->_nr_folios++;
ractl->_nr_pages += min_nrpages;
i += min_nrpages;
}
@@ -473,6 +475,7 @@ static inline int ra_alloc_folio(struct readahead_control *ractl, pgoff_t index,
return err;
}

+ ractl->_nr_folios++;
ractl->_nr_pages += 1UL << order;
ractl->_workingset |= folio_test_workingset(folio);
return 0;
@@ -822,6 +825,7 @@ void readahead_expand(struct readahead_control *ractl,
ractl->_workingset = true;
psi_memstall_enter(&ractl->_pflags);
}
+ ractl->_nr_folios++;
ractl->_nr_pages += min_nrpages;
ractl->_index = folio->index;
}
@@ -851,6 +855,7 @@ void readahead_expand(struct readahead_control *ractl,
ractl->_workingset = true;
psi_memstall_enter(&ractl->_pflags);
}
+ ractl->_nr_folios++;
ractl->_nr_pages += min_nrpages;
if (ra) {
ra->size += min_nrpages;