mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Rik van Riel <riel@surriel.com>
To: linux-kernel@vger.kernel.org
Cc: Andrew Morton <akpm@linux-foundation.org>,
	David Hildenbrand <david@kernel.org>,
	Jason Gunthorpe <jgg@ziepe.ca>,
	John Hubbard <jhubbard@nvidia.com>, Peter Xu <peterx@redhat.com>,
	Suren Baghdasaryan <surenb@google.com>,
	Yuan-Hao Hsu <aa9736195201@gmail.com>,
	Christoph Hellwig <hch@infradead.org>,
	linux-mm@kvack.org
Subject: [RFC PATCH v5 0/8] batch lookups in follow_page_mask()
Date: Mon,  2 Nov 2026 14:30:18 -0500	[thread overview]
Message-ID: <20261102193026.3860700-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 fill an
array of pages, instead of a single struct page, so a walker can hand back
more than one page per call.

Patches 1 to 4 are preparation, no functional change:

  1: move __get_user_pages()'s open-coded pages[] fill and cache flush into a
     gup_fill_pages() helper, which the rest of the series reuses.
  2: convert 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(). Every path still handles one page.
  3: split the "grab a folio reference and store the pages" tail of
     follow_page_pte() into gup_grab_folio_pages(). Storing runs under the
     lock; the cache flushes run after it, via gup_flush_pages().
  4: split the "work out which page this PTE maps" half of follow_page_pte()
     into gup_lookup_pte(), leaving one unlock and one exit.

Patch 5 has the huge page paths store the page and leave the array fill to
follow_pud_mask()/follow_pmd_mask() after they unlock, so the cache flushes
happen outside the pud/pmd critical section.

Patch 6 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 try_grab_folio() call and subpage loop.

Patch 7 walks every PTE in a page table in one follow_page_pte() call instead
of one per page. The slots are stored under the lock and flushed after it is
dropped, so a whole-table hold does no cache maintenance under the spinlock.

Patch 8 adds gup_pte_batch_len() so a contiguous same-folio run is committed
with one refcount grab. This is the only patch whose benefit depends on folio
size; patch 7 alone covers plain base pages.

Patches 7 and 8 carry their own benchmark tables, both measured against the
base of the series, so the split between the two mechanisms is visible: the
single-call walk is worth 2.3x on base pages and 2.2x on 64 kB mTHP, and
refcount batching adds a further 5.9x on the mTHP case.

Yuan-Hao Hsu ran the v3 series through mm selftests (DEBUG_VM, PROVE_LOCKING),
a GUP-vs-mprotect/MADV_DONTNEED/MADV_COLLAPSE/fork race test, a mixed-mapping
core dump test, W=1/sparse and arm64/i386/ARM builds, all clean, and confirmed
the wins with pin_user_pages(FOLL_LONGTERM): 64 kB mTHP at 256 MB goes from
2318 to 249 us, 4 kB pages from 2361 to 1065 us, 2 MB THP unchanged.

v5:
 - rename the new helpers to gup_lookup_pte(), gup_pte_batch_len(), and
   gup_grab_folio_pages() (David)
 - rebase to 7.4-rc1
 - document that folio_mark_accessed() now runs once per run,
   leaving a freshly faulted large folio referenced but inactive after
   the first call (Yuan-Hao's measurement)
 - note (in patch 4) why the recorded no_page_table() call cannot newly trigger
   on a FOLL_WRITE failure (Suren's question; answered in changelog)
 - add Suren's Reviewed-by tags on patches 1, 2 and 5

Not in this series: a single bio_vec straight through pin_user_pages_fast
for iov_iter_extract_bvecs (Christoph's idea) stays separate work, as David
suggested. The series does not change dirty-marking semantics -- a batch
only gathers the dirty bits its PTEs already had -- so the wider question
of whether GUP should mark folios dirty at all stays where it was
(John Hubbard pointed out the balrog in the room).

Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: David Hildenbrand <david@kernel.org>
Cc: Jason Gunthorpe <jgg@ziepe.ca>
Cc: John Hubbard <jhubbard@nvidia.com>
Cc: Peter Xu <peterx@redhat.com>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Yuan-Hao Hsu <aa9736195201@gmail.com>
Cc: Christoph Hellwig <hch@infradead.org>
Cc: linux-mm@kvack.org
Link: https://lore.kernel.org/r/20260811025157.1632867-1-riel@surriel.com/ [RFC v3]
Link: https://lore.kernel.org/r/20260801031540.2742891-1-riel@surriel.com/ [RFC v2]
Link: https://lore.kernel.org/r/20260730035350.1fc95dd8@fangorn/ [RFC]
Suggested-by: David Hildenbrand <david@kernel.org>

Rik van Riel (8):
  mm/gup: break out gup_fill_pages() helper
  mm/gup: convert follow_page_mask() to return a long
  mm/gup: split out folio grab-and-store helper
  mm/gup: break out gup_lookup_pte() helper
  mm/gup: fill the pages array outside the pud/pmd lock
  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: batch contiguous same-folio PTEs into one refcount grab

             reply	other threads:[~2026-11-02 19:30 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-02 19:30 Rik van Riel [this message]
2026-11-02 19:30 ` [PATCH 1/8] mm/gup: break out gup_fill_pages() helper Rik van Riel
2026-11-02 19:30 ` [PATCH 2/8] mm/gup: convert follow_page_mask() to return a long Rik van Riel
2026-11-02 19:30 ` [PATCH 3/8] mm/gup: split out folio grab-and-store helper Rik van Riel
2026-11-02 19:30 ` [PATCH 4/8] mm/gup: break out gup_lookup_pte() helper Rik van Riel
2026-11-02 19:30 ` [PATCH 5/8] mm/gup: fill the pages array outside the pud/pmd lock Rik van Riel
2026-11-02 19:30 ` [PATCH 6/8] mm/gup: return a huge page's full count from follow_page_mask() Rik van Riel
2026-11-02 19:30 ` [PATCH 7/8] mm/gup: walk multiple PTEs per follow_page_pte() call Rik van Riel
2026-11-02 19:30 ` [PATCH 8/8] mm/gup: batch contiguous same-folio PTEs into one refcount grab 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=20261102193026.3860700-1-riel@surriel.com \
    --to=riel@surriel.com \
    --cc=aa9736195201@gmail.com \
    --cc=akpm@linux-foundation.org \
    --cc=david@kernel.org \
    --cc=hch@infradead.org \
    --cc=jgg@ziepe.ca \
    --cc=jhubbard@nvidia.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=peterx@redhat.com \
    --cc=surenb@google.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®