Skip to content

Commit c320dbb

Browse files
Dev Jainctmarinas
authored andcommitted
arm64/mm: Elide TLB flush in certain pte protection transitions
Currently arm64 does an unconditional TLB flush in mprotect(). This is not required for some cases, for example, when changing from PROT_NONE to PROT_READ | PROT_WRITE (a real usecase - glibc malloc does this to emulate growing into the non-main heaps), and unsetting uffd-wp in a range. Therefore, implement pte_needs_flush() for arm64, which is already implemented by some other arches as well. Running a userspace program changing permissions back and forth between PROT_NONE and PROT_READ | PROT_WRITE, and measuring the average time taken for the none->rw transition, I get a reduction from 3.2 microseconds to 2.85 microseconds, giving a 12.3% improvement. Reviewed-by: Kefeng Wang <wangkefeng.wang@huawei.com> Signed-off-by: Dev Jain <dev.jain@arm.com> Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
1 parent 1b21445 commit c320dbb

1 file changed

Lines changed: 27 additions & 0 deletions

File tree

arch/arm64/include/asm/tlbflush.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -524,6 +524,33 @@ static inline void arch_tlbbatch_add_pending(struct arch_tlbflush_unmap_batch *b
524524
{
525525
__flush_tlb_range_nosync(mm, start, end, PAGE_SIZE, true, 3);
526526
}
527+
528+
static inline bool __pte_flags_need_flush(ptdesc_t oldval, ptdesc_t newval)
529+
{
530+
ptdesc_t diff = oldval ^ newval;
531+
532+
/* invalid to valid transition requires no flush */
533+
if (!(oldval & PTE_VALID))
534+
return false;
535+
536+
/* Transition in the SW bits requires no flush */
537+
diff &= ~PTE_SWBITS_MASK;
538+
539+
return diff;
540+
}
541+
542+
static inline bool pte_needs_flush(pte_t oldpte, pte_t newpte)
543+
{
544+
return __pte_flags_need_flush(pte_val(oldpte), pte_val(newpte));
545+
}
546+
#define pte_needs_flush pte_needs_flush
547+
548+
static inline bool huge_pmd_needs_flush(pmd_t oldpmd, pmd_t newpmd)
549+
{
550+
return __pte_flags_need_flush(pmd_val(oldpmd), pmd_val(newpmd));
551+
}
552+
#define huge_pmd_needs_flush huge_pmd_needs_flush
553+
527554
#endif
528555

529556
#endif

0 commit comments

Comments
 (0)