[PATCH v2 13/15] riscv/mm: remove redundant TLB flush in napotpte_convert
Yunhui Cui <[email protected]> Thu, 16 Jul 2026 20:41:48 +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 | <e55fb906990083b05272648f5299514a68cf8456.1784201104.git.cuiyunhui@bytedance.com> |
napotpte_convert() switches a NAPOT block between the Svnapot encoding and the equivalent set of base PTEs. The conversion itself preserves the effective translations: PFNs and permissions are kept the same while the page-table representation changes. Do not issue an SFENCE.VMA in the middle of this representation change. For partial updates, such as unfolding a writable NAPOT block before write-protecting one subrange, a flush at conversion time would not be the operation that enforces the final permission downgrade. Writable base-PTE translations could still be refilled after the conversion and before the subrange is write-protected. The required TLB maintenance belongs to the operation that actually changes the effective mapping. The RISC-V privileged architecture discussion clarifies that Svnapot is an encoding of a naturally aligned range. When napotpte_convert() only switches between the NAPOT encoding and the corresponding set of base PTEs for the same effective translations, the conversion itself does not require an extra TLB invalidation beyond the usual page-table update rules. Link: https://lists.riscv.org/g/tech-privileged/message/2950 Signed-off-by: Yunhui Cui <[email protected]> --- arch/riscv/mm/contpte.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/arch/riscv/mm/contpte.c b/arch/riscv/mm/contpte.c index b0b8ff0aade3a..8289f39d6e188 100644 --- a/arch/riscv/mm/contpte.c +++ b/arch/riscv/mm/contpte.c @@ -129,7 +129,7 @@ static pte_t __get_and_clear_full_ptes(struct mm_struct *mm, static void napotpte_convert(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t target) { - unsigned long start_addr, end, ptent_addr; + unsigned long start_addr, ptent_addr; pte_t *start_ptep; pte_t ptent, pte; unsigned int i, nr; @@ -137,7 +137,6 @@ static void napotpte_convert(struct mm_struct *mm, unsigned long addr, start_addr = napot_align_addr(addr); start_ptep = napot_align_ptep(ptep); nr = napotpte_pte_num(); - end = start_addr + napotpte_size(); for (i = 0; i < nr; i++) { ptent_addr = start_addr + i * PAGE_SIZE; @@ -150,8 +149,15 @@ static void napotpte_convert(struct mm_struct *mm, unsigned long addr, target = pte_mkyoung(target); } - flush_tlb_mm_range(mm, start_addr, end, PAGE_SIZE); - + /* + * This conversion only changes the representation of the same + * effective translations: NAPOT encoding <-> equivalent base PTEs. + * A flush here would not replace the TLB maintenance required by a + * later permission downgrade, because writable base-PTE translations + * could be refilled after this conversion and before that downgrade. + * Leave TLB invalidation to the operation that changes the effective + * mapping. + */ page_table_check_ptes_set(mm, start_addr, start_ptep, target, nr); if (pte_napot(target)) { for (i = 0; i < nr; i++) -- 2.39.5