With the relevant kvm cap enabled, EPT violations will exit to userspace w/ reason KVM_EXIT_MEMORY_FAULT instead of resolving the fault via slow get_user_pages. Signed-off-by: Anish Moorthy <amoorthy@xxxxxxxxxx> Suggested-by: James Houghton <jthoughton@xxxxxxxxxx> --- arch/x86/kvm/mmu/mmu.c | 23 ++++++++++++++++++++--- arch/x86/kvm/x86.c | 1 + 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index aeb240b339f54..28af8d60adee6 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -4201,6 +4201,7 @@ static int __kvm_faultin_pfn(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault { struct kvm_memory_slot *slot = fault->slot; bool async; + bool mem_fault_nowait; /* * Retry the page fault if the gfn hit a memslot that is being deleted @@ -4230,9 +4231,25 @@ static int __kvm_faultin_pfn(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault } async = false; - fault->pfn = __gfn_to_pfn_memslot(slot, fault->gfn, false, false, &async, - fault->write, &fault->map_writable, - &fault->hva); + mem_fault_nowait = memory_faults_enabled(vcpu->kvm); + + fault->pfn = __gfn_to_pfn_memslot( + slot, fault->gfn, + mem_fault_nowait, + false, + mem_fault_nowait ? NULL : &async, + fault->write, &fault->map_writable, + &fault->hva); + + if (mem_fault_nowait) { + if (fault->pfn == KVM_PFN_ERR_FAULT) { + vcpu->run->exit_reason = KVM_EXIT_MEMORY_FAULT; + vcpu->run->memory_fault.gpa = fault->gfn << PAGE_SHIFT; + vcpu->run->memory_fault.size = PAGE_SIZE; + } + return RET_PF_CONTINUE; + } + if (!async) return RET_PF_CONTINUE; /* *pfn has correct page already */ diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 508074e47bc0e..fe39ab2af5db4 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -4427,6 +4427,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) case KVM_CAP_VAPIC: case KVM_CAP_ENABLE_CAP: case KVM_CAP_VM_DISABLE_NX_HUGE_PAGES: + case KVM_CAP_MEM_FAULT_NOWAIT: r = 1; break; case KVM_CAP_EXIT_HYPERCALL: -- 2.39.1.581.gbfd45094c4-goog