[PATCH v2 10/15] mm/gup: add fast-GUP specific lockless PTE helpers
Yunhui Cui <[email protected]> Thu, 16 Jul 2026 20:41:45 +0800
| Newsgroups | org.kernel.vger.linux-efi,org.infradead.lists.kvm-riscv,org.infradead.lists.linux-arm-kernel,org.infradead.lists.linux-riscv,org.kernel.vger.kvm,org.kernel.vger.linux-arch,org.kernel.vger.linux-kernel,org.kernel.vger.linux-perf-users,org.kvack.linux-mm |
|---|---|
| Message-ID | <138d74aa9863ae8ff445e16a2798d062895b75bc.1784201104.git.cuiyunhui@bytedance.com> |
fast-GUP snapshots a PTE without holding the PTL, pins the page, and then revalidates that the PTE did not change. Keep both reads under the same lockless PTE semantics by defaulting the fast-GUP revalidation to ptep_get_lockless(). Introduce fast-GUP specific PTE snapshot and revalidation helpers. The default implementation preserves the existing ptep_get_lockless() semantics, while allowing architectures to override the helpers when the public lockless getter provides extra semantics that fast-GUP does not consume. Signed-off-by: Yunhui Cui <[email protected]> --- include/linux/pgtable.h | 18 ++++++++++++++++++ mm/gup.c | 6 ++++-- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/include/linux/pgtable.h b/include/linux/pgtable.h index da14328093a86..62943fcbf7046 100644 --- a/include/linux/pgtable.h +++ b/include/linux/pgtable.h @@ -813,6 +813,24 @@ static inline pte_t ptep_get_lockless(pte_t *ptep) } #endif +#ifndef gup_ptep_get_lockless +static inline pte_t gup_ptep_get_lockless(pte_t *ptep, pte_t *rawp) +{ + pte_t pte = ptep_get_lockless(ptep); + + *rawp = pte; + + return pte; +} +#endif + +#ifndef gup_ptep_revalidate +static inline bool gup_ptep_revalidate(pte_t *ptep, pte_t raw_pte) +{ + return pte_val(raw_pte) == pte_val(ptep_get_lockless(ptep)); +} +#endif + #ifndef pmdp_get_lockless static inline pmd_t pmdp_get_lockless(pmd_t *pmdp) { diff --git a/mm/gup.c b/mm/gup.c index 99902c15703b0..72fb147193e55 100644 --- a/mm/gup.c +++ b/mm/gup.c @@ -2842,10 +2842,12 @@ static int gup_fast_pte_range(pmd_t pmd, pmd_t *pmdp, unsigned long addr, if (!ptep) return 0; do { - pte_t pte = ptep_get_lockless(ptep); + pte_t raw_pte, pte; struct page *page; struct folio *folio; + pte = gup_ptep_get_lockless(ptep, &raw_pte); + /* * Always fallback to ordinary GUP on PROT_NONE-mapped pages: * pte_access_permitted() better should reject these pages @@ -2871,7 +2873,7 @@ static int gup_fast_pte_range(pmd_t pmd, pmd_t *pmdp, unsigned long addr, goto pte_unmap; if (unlikely(pmd_val(pmd) != pmd_val(pmdp_get_lockless(pmdp))) || - unlikely(pte_val(pte) != pte_val(ptep_get_lockless(ptep)))) { + unlikely(!gup_ptep_revalidate(ptep, raw_pte))) { gup_put_folio(folio, 1, flags); goto pte_unmap; } -- 2.39.5