[RFC PATCH v2 15/18] mm/filemap: don't store f_ra.prev_pos for FMODE_RANDOM files
From: Kiryl Shutsemau (Meta)
Date: Wed Nov 04 2026 - 08:13:05 EST
filemap_read() writes the end of every read to file->f_ra.prev_pos, in
the cache line that fdget() and fdput() write when threads share the
file table.
Applications that read a file at random offsets from many threads, such
as RocksDB, set POSIX_FADV_RANDOM on it. Readahead then never reads
prev_pos: page_cache_sync_ra() forces the read first.
Skip the store for such files after a read that filemap_read_rcu() did
in full: without folio references, the file's line is what the threads
contend on. Keep it on the slow path, which takes folio references:
skipping it there made reads slower in my testing.
filemap_read() compares the start of a read with prev_pos, to tell a
read that goes on in the same folio from another access to it. On an
FMODE_RANDOM file it can now be stale; with many threads on one file it
was another thread's read already.
Signed-off-by: Kiryl Shutsemau (Meta) <kas@xxxxxxxxxx>
---
mm/filemap.c | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/mm/filemap.c b/mm/filemap.c
index 182ae7d5db56..5998de3d6697 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -3078,8 +3078,13 @@ ssize_t filemap_read(struct kiocb *iocb, struct iov_iter *iter,
if (fast_read) {
already_read += fast_read;
last_pos = iocb->ki_pos;
- if (!iov_iter_count(iter))
- goto out;
+ if (!iov_iter_count(iter)) {
+ file_accessed(filp);
+ /* Readahead of a random file ignores it: skip the shared store */
+ if (!(filp->f_mode & FMODE_RANDOM))
+ ra->prev_pos = last_pos;
+ return already_read;
+ }
}
do {
@@ -3161,7 +3166,6 @@ ssize_t filemap_read(struct kiocb *iocb, struct iov_iter *iter,
}
} while (iov_iter_count(iter) && iocb->ki_pos < isize && !error);
-out:
file_accessed(filp);
ra->prev_pos = last_pos;
return already_read ? already_read : error;
--
2.54.0