[PATCH 2/2] mm/filemap: extend VM_SEQ_READ readahead below descending faults
From: Qiliang Yuan
Date: Thu Oct 22 2026 - 10:01:41 EST
On a VM_SEQ_READ mapping, a synchronous fault reads ahead from the
faulting page towards higher offsets through page_cache_sync_ra().
A reader that moves towards lower offsets, such as memmove() copying
backwards out of a mapping, finds the pages above the fault already
cached, so each of its faults reads a single new page.
page_cache_sync_ra() also looks for a stream only below the fault and
takes it for a small random read.
When the page above the fault is already cached, read the window of
ra_pages that ends at the faulting page instead, without a readahead
mark.
Reading one byte from each page of a 2 GiB file, last page first, in a
MADV_SEQUENTIAL mapping with a cold page cache, read_ahead_kb 8192:
before after
time 50.28 s 0.76 s
major faults 524291 260
Signed-off-by: Qiliang Yuan <odys.yuan@xxxxxxxxx>
---
mm/filemap.c | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/mm/filemap.c b/mm/filemap.c
index 8a7d1238ae75d..62d507f96f22b 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -3384,7 +3384,19 @@ static struct file *do_sync_mmap_readahead(struct vm_fault *vmf)
if (vm_flags & VM_SEQ_READ) {
fpin = maybe_unlock_mmap_for_io(vmf, fpin);
- page_cache_sync_ra(&ractl, ra->ra_pages);
+ if (!filemap_descending(mapping, vmf->pgoff, 1)) {
+ page_cache_sync_ra(&ractl, ra->ra_pages);
+ return fpin;
+ }
+ /* Read the window that ends at the faulting page */
+ ra->start = vmf->pgoff + 1 -
+ min_t(unsigned long, ra->ra_pages,
+ vmf->pgoff + 1);
+ ra->size = vmf->pgoff + 1 - ra->start;
+ ra->async_size = 0;
+ ra->order = 0;
+ ractl._index = ra->start;
+ page_cache_ra_order(&ractl, ra);
return fpin;
}
}
--
2.43.0