Re: [External] Re: [PATCH v2 10/15] mm/gup: add fast-GUP specific lockless PTE helpers
yunhui cui <[email protected]> Thu, 6 Aug 2026 19:03:33 +0800
| Newsgroups | org.kernel.vger.linux-perf-users,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-efi,org.kernel.vger.linux-kernel,org.kvack.linux-mm |
|---|---|
| Message-ID | <CAEEQ3wk62WBSJb5JcnPJoVSb+JQq3ZcE4CRmqqTvkAO20XFjbg@mail.gmail.com> |
Hi Lorenzo, On Thu, Aug 6, 2026 at 3:35 PM Lorenzo Stoakes (ARM) <[email protected]> wrote: > > +cc literally everybody you failed to contact...! > > Why on earth are you doing sending a series like this which changes core mm, > non-RFC and at v2 to boot, without bothering to Cc relevant people? > > I am also very confused as to why you are sending an ostensible RISC-V series > then changing how core mm works to fit it, that's not how that works. > > And if you're seeking to change core mm send it as an RFC! > > On Thu, Jul 16, 2026 at 08:41:45PM +0800, Yunhui Cui wrote: > > 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(). > > Why?... Thanks for the review. Let me first explain the motivation behind patch 10/15, and then address the RFC/Cc and naming issues. The goal of this patchset is to let RISC-V Svnapot provide contiguous PTE semantics similar to arm64 contpte: generic MM should still see a normal per-page PTE view, while RISC-V can fold eligible PTE ranges into the Svnapot/NAPOT encoding underneath. Because of that, the RISC-V public ptep_get_lockless() may, for a Svnapot PTE, return the sub-PTE for the current address expected by generic MM, after checking the whole NAPOT range for consistency and aggregating block-wide A/D bits. fast-GUP has a narrower requirement. It needs the PTE for the current address for permission/PFN/page lookup, then pins the page, and finally checks that the page table entry it relied on did not change during the pin. fast-GUP does not consume the block-wide A/D aggregation. If fast-GUP uses the public ptep_get_lockless() for both the initial read and the revalidation, it pays the cost of the NAPOT range scan and A/D aggregation in the fast path, even though that information is not used. So patch 10/15 is not trying to wrap a simple equality check. The intent is to separate two semantics: the current-address PTE consumed by fast-GUP, and the original PTE snapshot used for post-pin revalidation. On normal architectures these are the same value, and the default implementation preserves the existing ptep_get_lockless() behavior. On RISC-V Svnapot, the value consumed by fast-GUP is the sub-PTE, while revalidation compares whether the raw snapshot has changed. Patch 11/15 is the RISC-V use of this hook. It avoids the public ptep_get_lockless() block-wide A/D aggregation path in fast-GUP, while still keeping correctness through raw snapshot revalidation. In the 64K THP always mode, fio 4K random direct read improved from 2.615M IOPS / 9.97GiB/s to 2.874M IOPS / 11.0GiB/s, and the average clat dropped from 95.54 usec to 86.97 usec. Regarding the RFC/Cc issue, you are right, I handled that poorly. Although this series is mainly about RISC-V Svnapot, patch 10/15 adds a generic MM/GUP helper and patch 12/15 also changes the arm64 contpte fast-GUP path, so they are no longer RISC-V-local changes. I was worried that the large list of individual recipients from get_maintainer.pl would create too much noise, so I mostly kept the mailing lists and dropped some individual Cc's. That was a bad call; the relevant maintainers/reviewers should have been Cc'ed explicitly. Sorry about that. For the next version, I will split the generic fast-GUP helper out as a separate RFC, add the relevant MM/GUP/arm64/RISC-V maintainers and reviewers to Cc, and explain the semantic difference between the PTE consumed by fast-GUP and the post-pin revalidation snapshot. If I keep the arm64 optimization, I will include the arm64 maintainers/reviewers in that RFC; otherwise I will drop it from the RISC-V series for now. I will also improve the naming, such as `rawp`/`raw_pte`, and add comments to make the snapshot semantics clearer. > > > > > 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 > > > > Of course, no comments, helpful! > > > +#ifndef gup_ptep_get_lockless > > +static inline pte_t gup_ptep_get_lockless(pte_t *ptep, pte_t *rawp) > > rawp? This is terrible naming. > > And 'gup_ptep_get_lockless()' is worse. What on earth is this function meant to > do? And why is 'gup lockless' considered different from lockless? > > And you return the value twice, because of course you do. Why? Who knows. > > > +{ > > + 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)); > > +} > > Again this naming is utterly terrible and I'm at a loss as to why on earth > you're doing this? > > We don't need to abstract equality checks? > > > +#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; > > What on earth is a 'raw' 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))) { > > Why do we need to refadctor a comparison between a local variable and a lockless > get? > > I'm just so confused by what on earth this patch is meant to be or why it's here... > > > gup_put_folio(folio, 1, flags); > > goto pte_unmap; > > } > > -- > > 2.39.5 > > > > > > _______________________________________________ > > linux-riscv mailing list > > [email protected] > > http://lists.infradead.org/mailman/listinfo/linux-riscv > > -- > Cheers, Lorenzo Thanks, Yunhui