riscv: mm: try VMA lock-based page fault handling first
authorJisheng Zhang <jszhang@kernel.org>
Tue, 23 May 2023 16:59:42 +0000 (00:59 +0800)
committerPalmer Dabbelt <palmer@rivosinc.com>
Tue, 20 Jun 2023 15:10:13 +0000 (08:10 -0700)
Attempt VMA lock-based page fault handling first, and fall back to the
existing mmap_lock-based handling if that fails.

A simple running the ebizzy benchmark on Lichee Pi 4A shows that
PER_VMA_LOCK can improve the ebizzy benchmark by about 32.68%. In
theory, the more CPUs, the bigger improvement, but I don't have any
HW platform which has more than 4 CPUs.

This is the riscv variant of "x86/mm: try VMA lock-based page fault
handling first".

Signed-off-by: Jisheng Zhang <jszhang@kernel.org>
Reviewed-by: Guo Ren <guoren@kernel.org>
Reviewed-by: Suren Baghdasaryan <surenb@google.com>
Link: https://lore.kernel.org/r/20230523165942.2630-1-jszhang@kernel.org
Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>
arch/riscv/Kconfig
arch/riscv/mm/fault.c

index a3d54cd..a9e8b69 100644 (file)
@@ -44,6 +44,7 @@ config RISCV
        select ARCH_SUPPORTS_DEBUG_PAGEALLOC if MMU
        select ARCH_SUPPORTS_HUGETLBFS if MMU
        select ARCH_SUPPORTS_PAGE_TABLE_CHECK if MMU
+       select ARCH_SUPPORTS_PER_VMA_LOCK if MMU
        select ARCH_USE_MEMTEST
        select ARCH_USE_QUEUED_RWLOCKS
        select ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT if MMU
index b023fb3..e52ed89 100644 (file)
@@ -274,6 +274,36 @@ void handle_page_fault(struct pt_regs *regs)
                flags |= FAULT_FLAG_WRITE;
        else if (cause == EXC_INST_PAGE_FAULT)
                flags |= FAULT_FLAG_INSTRUCTION;
+#ifdef CONFIG_PER_VMA_LOCK
+       if (!(flags & FAULT_FLAG_USER))
+               goto lock_mmap;
+
+       vma = lock_vma_under_rcu(mm, addr);
+       if (!vma)
+               goto lock_mmap;
+
+       if (unlikely(access_error(cause, vma))) {
+               vma_end_read(vma);
+               goto lock_mmap;
+       }
+
+       fault = handle_mm_fault(vma, addr, flags | FAULT_FLAG_VMA_LOCK, regs);
+       vma_end_read(vma);
+
+       if (!(fault & VM_FAULT_RETRY)) {
+               count_vm_vma_lock_event(VMA_LOCK_SUCCESS);
+               goto done;
+       }
+       count_vm_vma_lock_event(VMA_LOCK_RETRY);
+
+       if (fault_signal_pending(fault, regs)) {
+               if (!user_mode(regs))
+                       no_context(regs, addr);
+               return;
+       }
+lock_mmap:
+#endif /* CONFIG_PER_VMA_LOCK */
+
 retry:
        mmap_read_lock(mm);
        vma = find_vma(mm, addr);
@@ -343,6 +373,9 @@ good_area:
 
        mmap_read_unlock(mm);
 
+#ifdef CONFIG_PER_VMA_LOCK
+done:
+#endif
        if (unlikely(fault & VM_FAULT_ERROR)) {
                tsk->thread.bad_cause = cause;
                mm_fault_error(regs, addr, fault);