Page faults which occured by the guest running on slave CPUs cannot be handled on slave CPUs because it is running on idle process context.
With this patch, the page fault happened in a slave CPU is notified to online CPU using struct kvm_access_fault, and is handled after the user-process for the guest is resumed on an online CPU. Signed-off-by: Tomoki Sekiyama <tomoki.sekiyama...@hitachi.com> Cc: Avi Kivity <a...@redhat.com> Cc: Marcelo Tosatti <mtosa...@redhat.com> Cc: Thomas Gleixner <t...@linutronix.de> Cc: Ingo Molnar <mi...@redhat.com> Cc: "H. Peter Anvin" <h...@zytor.com> --- arch/x86/include/asm/kvm_host.h | 15 +++++++++++++++ arch/x86/kvm/mmu.c | 13 +++++++++++++ arch/x86/kvm/x86.c | 10 ++++++++++ 3 files changed, 38 insertions(+), 0 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 4291954..80f7b3b 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -66,6 +66,11 @@ #define UNMAPPED_GVA (~(gpa_t)0) +#ifdef CONFIG_SLAVE_CPU +/* Requests to handle VM exit on online cpu */ +#define KVM_REQ_HANDLE_PF 32 +#endif + /* KVM Hugepage definitions for x86 */ #define KVM_NR_PAGE_SIZES 3 #define KVM_HPAGE_GFN_SHIFT(x) (((x) - 1) * 9) @@ -405,6 +410,16 @@ struct kvm_vcpu_arch { u8 nr; } interrupt; +#ifdef CONFIG_SLAVE_CPU + /* used for recording page fault on offline CPU */ + struct kvm_access_fault { + gva_t cr2; + u32 error_code; + void *insn; + int insn_len; + } page_fault; +#endif + int halt_request; /* real mode on Intel only */ int cpuid_nent; diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index 6139e1d..a179ebc 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -3785,6 +3785,19 @@ int kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gva_t cr2, u32 error_code, int r, emulation_type = EMULTYPE_RETRY; enum emulation_result er; +#ifdef CONFIG_SLAVE_CPU + if (cpu_slave(smp_processor_id())) { + /* Page fault must be handled on user-process context. */ + r = -EFAULT; + vcpu->arch.page_fault.cr2 = cr2; + vcpu->arch.page_fault.error_code = error_code; + vcpu->arch.page_fault.insn = insn; + vcpu->arch.page_fault.insn_len = insn_len; + kvm_make_request(KVM_REQ_HANDLE_PF, vcpu); + goto out; + } +#endif + r = vcpu->arch.mmu.page_fault(vcpu, cr2, error_code, false); if (r < 0) goto out; diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index ecd474a..7b9f2a5 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -5552,6 +5552,16 @@ static int vcpu_enter_guest_slave(struct kvm_vcpu *vcpu, r = arg.ret; *apf_pending = arg.apf_pending; + if (r == -EFAULT && kvm_check_request(KVM_REQ_HANDLE_PF, vcpu)) { + pr_debug("handling page fault request @%p\n", + (void *)vcpu->arch.page_fault.cr2); + r = kvm_mmu_page_fault(vcpu, + vcpu->arch.page_fault.cr2, + vcpu->arch.page_fault.error_code, + vcpu->arch.page_fault.insn, + vcpu->arch.page_fault.insn_len); + } + return r; } -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html