From: Rik van Riel <riel@surriel.com>
To: linux-kernel@vger.kernel.org,
Andrew Morton <akpm@linux-foundation.org>,
David Hildenbrand <david@kernel.org>
Cc: kernel-team@meta.com, Rik van Riel <riel@surriel.com>,
Jason Gunthorpe <jgg@ziepe.ca>,
John Hubbard <jhubbard@nvidia.com>, Peter Xu <peterx@redhat.com>,
linux-mm@kvack.org, Lorenzo Stoakes <ljs@kernel.org>
Subject: [PATCH 0/5] mm/gup: batch contiguous pages in follow_page_mask()
Date: Fri, 31 Jul 2026 23:15:35 -0400 [thread overview]
Message-ID: <20260801031540.2742891-1-riel@surriel.com> (raw)
follow_page_mask() walks the page tables one page at a time, even when
the caller asked for a whole run of contiguous pages. Every page of a
large folio re-enters the pmd/pud/pte walk and re-takes the page table
lock.
This series changes follow_page_mask() to return a page count and a
new @end argument bounding how many pages remain, instead of a single
struct page, so a walker can hand back more than one page per call.
Patch 1 converts the follow_page_mask()/follow_p4d_mask()/
follow_pud_mask()/follow_pmd_mask()/follow_page_pte() call chain to
return a long instead of a struct page pointer or ERR_PTR(), with no
functional change: every path still handles exactly one page.
Patch 2 is pure code motion, splitting the "commit to a resolved page"
tail of follow_page_pte() into its own follow_page_pte_commit(), no
functional change.
Patch 3 adds gup_fill_pages(), a small helper that fills pages[] and
flushes caches for a run of subpages, and converts the three existing
per-page call sites to use it with nr == 1, no functional change.
Patch 4 has follow_huge_pud()/follow_huge_pmd() report the huge page's
real subpage count instead of a separate *page_mask output, and
retires *page_mask and __get_user_pages()'s dead second
try_grab_folio() call and subpage loop.
It also defers gup_fill_pages() past the pud/pmd unlock, so a 1 GB
PUD-mapped folio doesn't hold that lock for a full array fill and
cache flush.
Patch 5 adds follow_pte_batch() and has follow_page_pte() call it once
per contiguous same-folio run instead of once per page, so a
PTE-mapped mTHP no longer restarts the walk and re-takes the PTE lock
per subpage.
This is the only patch that changes the number of page table walks or
lock acquisitions.
Benchmarked with mm/gup_test.c (PIN_LONGTERM_BENCHMARK, pin_user_pages
+ FOLL_LONGTERM, 256 MB region, median of 16 runs, folio formation
verified via the per-size anon_fault_alloc counter):
before after
4 kB base pages 2721 us 1198 us (2.3x)
64 kB mTHP 2929 us 201 us (14.6x)
2 MB THP 73 us 69 us (flat)
The 4 kB result comes entirely from patch 5 merging two separate
try_grab_folio() calls and lock acquisitions into one; folio size and
PTE batching play no part in it.
64 kB mTHP adds the walk-restart avoidance on top. 2 MB THP is
unaffected, since follow_huge_pmd() already handled it in one call.
Patch 4's lock-hold-time change is a scalability argument, not a
measured one -- it is not visible in this single-threaded benchmark.
Suggested-by: David Hildenbrand <david@kernel.org>
Rik van Riel (5):
mm/gup: convert follow_page_mask() to return a long
mm/gup: split follow_page_pte_commit() out of follow_page_pte()
mm/gup: add gup_fill_pages() and use it
mm/gup: return a huge page's full count from follow_page_mask()
mm/gup: walk multiple PTEs per follow_page_pte() call
mm/gup.c | 532 +++++++++++++++++++++++++++++++++----------------------
1 file changed, 322 insertions(+), 210 deletions(-)
base-commit: fc02acf6ac0c
--
2.53.0-Meta
next reply other threads:[~2026-08-01 3:16 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-01 3:15 Rik van Riel [this message]
2026-08-01 3:15 ` [PATCH 1/5] mm/gup: convert follow_page_mask() to return a long Rik van Riel
2026-08-01 3:15 ` [PATCH 2/5] mm/gup: split follow_page_pte_commit() out of follow_page_pte() Rik van Riel
2026-08-01 3:15 ` [PATCH 3/5] mm/gup: add gup_fill_pages() and use it Rik van Riel
2026-08-01 3:15 ` [PATCH 4/5] mm/gup: return a huge page's full count from follow_page_mask() Rik van Riel
2026-08-01 3:15 ` [PATCH 5/5] mm/gup: walk multiple PTEs per follow_page_pte() call Rik van Riel
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260801031540.2742891-1-riel@surriel.com \
--to=riel@surriel.com \
--cc=akpm@linux-foundation.org \
--cc=david@kernel.org \
--cc=jgg@ziepe.ca \
--cc=jhubbard@nvidia.com \
--cc=kernel-team@meta.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=ljs@kernel.org \
--cc=peterx@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.