[PATCH v2 11/15] riscv: mm: avoid Svnapot A/D aggregation in fast-GUP
Yunhui Cui <[email protected]> Thu, 16 Jul 2026 20:41:46 +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 | <95699db9c9b90fd1f95310e9d95b000eb8cfc616.1784201104.git.cuiyunhui@bytedance.com> |
fast-GUP only needs the PTE state for the current virtual address and revalidates the raw PTE after pinning the page. It does not consume the block-wide accessed/dirty aggregation provided by the public Svnapot lockless getter. Override the fast-GUP PTE helpers to translate a NAPOT PTE into the current sub-PTE without scanning the whole NAPOT block. Keep the public ptep_get_lockless() semantics unchanged for other lockless users. With 64K THP enabled in always mode, fio 4K random direct read throughput improves by about 10% over the previous implementation on the same system, from 2.615M to 2.874M IOPS and from 9.97GiB/s to 11.0GiB/s, while average clat drops from 95.54 usec to 86.97 usec. Signed-off-by: Yunhui Cui <[email protected]> --- arch/riscv/include/asm/pgtable.h | 20 ++++++++++++++++++++ arch/riscv/mm/contpte.c | 9 +++++++++ 2 files changed, 29 insertions(+) diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h index dd56c20a817bb..3727c148fa0fc 100644 --- a/arch/riscv/include/asm/pgtable.h +++ b/arch/riscv/include/asm/pgtable.h @@ -597,6 +597,7 @@ void __napotpte_try_unfold(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pte); pte_t napotpte_ptep_get(pte_t *ptep, pte_t orig_pte); pte_t napotpte_ptep_get_lockless(pte_t *ptep); +pte_t napotpte_ptep_get_gup_fast(pte_t *ptep, pte_t orig_pte); void napotpte_set_ptes(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pte, unsigned int nr); void napotpte_clear_full_ptes(struct mm_struct *mm, unsigned long addr, @@ -956,6 +957,25 @@ static inline pte_t ptep_get_lockless(pte_t *ptep) return napotpte_ptep_get_lockless(ptep); } +#define gup_ptep_get_lockless 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; + + if (likely(!pte_present_napot(pte))) + return pte; + + return napotpte_ptep_get_gup_fast(ptep, pte); +} + +#define gup_ptep_revalidate 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)); +} + #define set_ptes set_ptes static inline void set_ptes(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pteval, unsigned int nr) diff --git a/arch/riscv/mm/contpte.c b/arch/riscv/mm/contpte.c index 0f66426b0ecfd..b0b8ff0aade3a 100644 --- a/arch/riscv/mm/contpte.c +++ b/arch/riscv/mm/contpte.c @@ -413,6 +413,15 @@ pte_t napotpte_ptep_get_lockless(pte_t *orig_ptep) } EXPORT_SYMBOL(napotpte_ptep_get_lockless); +pte_t napotpte_ptep_get_gup_fast(pte_t *orig_ptep, pte_t orig_pte) +{ + if (!napot_hw_supported() || !pte_present_napot(orig_pte)) + return orig_pte; + + return napotpte_subpte(orig_ptep, orig_pte); +} +EXPORT_SYMBOL(napotpte_ptep_get_gup_fast); + unsigned int napotpte_pte_batch_hint_from_pte(pte_t *ptep, pte_t orig_pte, fpb_t flags) { -- 2.39.5