Re: [RFC PATCH v3 0/8] batch lookups in follow_page_mask()

From: Yuan-Hao Hsu

Date: Wed Oct 14 2026 - 17:46:05 EST


On Mon, 10 Aug 2026 22:51:49 -0400, Rik van Riel wrote:
> This series changes follow_page_mask() to return a page count and a fill an
> array of pages, instead of a single struct page, so a walker can hand back
> more than one page per call.

Applied the series on current mainline (3857c2fe5449) and ran it
through the mm selftests with DEBUG_VM and PROVE_LOCKING, a race test
that drives get_user_pages() and pin_user_pages(FOLL_LONGTERM)
against mprotect/MADV_DONTNEED/MADV_COLLAPSE/fork on 64 kB and 2 MB
folios, and a core dump of mixed 4 kB/64 kB/PMD mappings with holes
and a PROT_NONE page. All of it passes with no unexpected warnings,
and the fast path numbers did not move. W=1, sparse and the cross
builds for arm64 (4K/16K/64K), i386 (with and without PAE) and ARM
nommu are clean.

pin_user_pages(FOLL_LONGTERM) over 64 kB mTHP, the whole region in
one call, median of 15, base -> series:

16 MB 138 -> 15 us
64 MB 566 -> 60 us
256 MB 2318 -> 249 us

(4 kB pages at 256 MB: 2361 -> 1065 us; 2 MB THP unchanged.)

One thing worth knowing from the 256 MB run: the unpin side goes from
94 to 180 us. The unpin time is the same on both kernels at 16 MB
and 64 MB, which points to a cache effect rather than extra work: the
batched walk no longer touches the tail pages' struct page, so
gup_folio_next() in unpin_user_pages() takes those misses instead.
Net 2412 -> 429 us.

The one change I would make is on 7/8: the pages[] fill and the cache
flushes now run under the PTE lock, up to a whole page table per
hold, while 5/8 moves that same work out of the pmd/pud lock.
Details there.

Yuan-Hao Hsu