Re: Improve page refcount scalability

From: Kiryl Shutsemau

Date: Tue Oct 13 2026 - 18:52:07 EST


On Tue, Oct 13, 2026 at 11:43:14AM -0700, Linus Torvalds wrote:
> Comments?

There's a race in filemap_read_rcu_batch(). If the folio is replaced
under us with a new one and then i_size is extended, we can read data
that never got written there:

CPU0 CPU1
filemap_read()
filemap_read_rcu()
filemap_read_rcu_batch()
folio = xas_load() // A
test_bit(PG_rcu_free, A)
xas_reload() == A
fadvise(FADV_DONTNEED)
// A leaves the page cache, its
// free is deferred: A stays valid
write()
// page cache re-populated
// i_size extended
isize = i_size_read()
// i_size is extended
copy_page_to_iter(A)
// we read from old folio
// data that user never wrote

We need to re-check that the folio is still in the page cache after we
get the new i_size. See the patch below.

My branch contains a few more changes that address downstream effects of
RCU-freeing the page cache. But we can come back to that later once we get
agreement on the core mechanism.

diff --git a/mm/filemap.c b/mm/filemap.c
index b85de94a1b6e..0d9fcc35dc64 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -2956,6 +2956,8 @@ static bool filemap_read_rcu_batch(struct kiocb *iocb, struct iov_iter *iter,
isize = i_size_read(inode);
if (pos >= isize)
break;
+ if (xas_reload(&xas) != folio)
+ break;
bytes = min_t(loff_t, isize - pos,
min_t(size_t, iov_iter_count(iter),
PAGE_SIZE - offset));
--
Kiryl Shutsemau / Kirill A. Shutemov