KVM: Retry fault before vmentry
authorGleb Natapov <gleb@redhat.com>
Sun, 17 Oct 2010 16:13:42 +0000 (18:13 +0200)
committerAvi Kivity <avi@redhat.com>
Wed, 12 Jan 2011 09:23:06 +0000 (11:23 +0200)
When page is swapped in it is mapped into guest memory only after guest
tries to access it again and generate another fault. To save this fault
we can map it immediately since we know that guest is going to access
the page. Do it only when tdp is enabled for now. Shadow paging case is
more complicated. CR[034] and EFER registers should be switched before
doing mapping and then switched back.

Acked-by: Rik van Riel <riel@redhat.com>
Signed-off-by: Gleb Natapov <gleb@redhat.com>
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
arch/x86/include/asm/kvm_host.h
arch/x86/kvm/mmu.c
arch/x86/kvm/paging_tmpl.h
arch/x86/kvm/x86.c
virt/kvm/async_pf.c

index b5f4c1a36d65955bbbe5756a68fe0a7cb82faaac..c3076bcf5ef7005de08691a8751d2b01f6823da2 100644 (file)
@@ -241,7 +241,7 @@ struct kvm_mmu {
        void (*new_cr3)(struct kvm_vcpu *vcpu);
        void (*set_cr3)(struct kvm_vcpu *vcpu, unsigned long root);
        unsigned long (*get_cr3)(struct kvm_vcpu *vcpu);
-       int (*page_fault)(struct kvm_vcpu *vcpu, gva_t gva, u32 err);
+       int (*page_fault)(struct kvm_vcpu *vcpu, gva_t gva, u32 err, bool no_apf);
        void (*inject_page_fault)(struct kvm_vcpu *vcpu);
        void (*free)(struct kvm_vcpu *vcpu);
        gpa_t (*gva_to_gpa)(struct kvm_vcpu *vcpu, gva_t gva, u32 access,
@@ -815,6 +815,8 @@ void kvm_arch_async_page_not_present(struct kvm_vcpu *vcpu,
                                     struct kvm_async_pf *work);
 void kvm_arch_async_page_present(struct kvm_vcpu *vcpu,
                                 struct kvm_async_pf *work);
+void kvm_arch_async_page_ready(struct kvm_vcpu *vcpu,
+                              struct kvm_async_pf *work);
 extern bool kvm_find_async_pf_gfn(struct kvm_vcpu *vcpu, gfn_t gfn);
 
 #endif /* _ASM_X86_KVM_HOST_H */
index 4ab04de5a76af12fae67d60c9bf4bf8df0437f9e..b2c60986a7ce361f33bedb52235367b8ffb3dfc4 100644 (file)
@@ -2570,7 +2570,7 @@ static gpa_t nonpaging_gva_to_gpa_nested(struct kvm_vcpu *vcpu, gva_t vaddr,
 }
 
 static int nonpaging_page_fault(struct kvm_vcpu *vcpu, gva_t gva,
-                               u32 error_code)
+                               u32 error_code, bool no_apf)
 {
        gfn_t gfn;
        int r;
@@ -2606,8 +2606,8 @@ static bool can_do_async_pf(struct kvm_vcpu *vcpu)
        return kvm_x86_ops->interrupt_allowed(vcpu);
 }
 
-static bool try_async_pf(struct kvm_vcpu *vcpu, gfn_t gfn, gva_t gva,
-                        pfn_t *pfn)
+static bool try_async_pf(struct kvm_vcpu *vcpu, bool no_apf, gfn_t gfn,
+                        gva_t gva, pfn_t *pfn)
 {
        bool async;
 
@@ -2618,7 +2618,7 @@ static bool try_async_pf(struct kvm_vcpu *vcpu, gfn_t gfn, gva_t gva,
 
        put_page(pfn_to_page(*pfn));
 
-       if (can_do_async_pf(vcpu)) {
+       if (!no_apf && can_do_async_pf(vcpu)) {
                trace_kvm_try_async_get_page(async, *pfn);
                if (kvm_find_async_pf_gfn(vcpu, gfn)) {
                        trace_kvm_async_pf_doublefault(gva, gfn);
@@ -2633,8 +2633,8 @@ static bool try_async_pf(struct kvm_vcpu *vcpu, gfn_t gfn, gva_t gva,
        return false;
 }
 
-static int tdp_page_fault(struct kvm_vcpu *vcpu, gva_t gpa,
-                               u32 error_code)
+static int tdp_page_fault(struct kvm_vcpu *vcpu, gva_t gpa, u32 error_code,
+                         bool no_apf)
 {
        pfn_t pfn;
        int r;
@@ -2656,7 +2656,7 @@ static int tdp_page_fault(struct kvm_vcpu *vcpu, gva_t gpa,
        mmu_seq = vcpu->kvm->mmu_notifier_seq;
        smp_rmb();
 
-       if (try_async_pf(vcpu, gfn, gpa, &pfn))
+       if (try_async_pf(vcpu, no_apf, gfn, gpa, &pfn))
                return 0;
 
        /* mmio */
@@ -3319,7 +3319,7 @@ int kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gva_t cr2, u32 error_code)
        int r;
        enum emulation_result er;
 
-       r = vcpu->arch.mmu.page_fault(vcpu, cr2, error_code);
+       r = vcpu->arch.mmu.page_fault(vcpu, cr2, error_code, false);
        if (r < 0)
                goto out;
 
index c45376dd041af7ee69bf47acb49045757f2941f0..d6b281e989b183b715247d9d976da89bd08fab8c 100644 (file)
@@ -527,8 +527,8 @@ out_gpte_changed:
  *  Returns: 1 if we need to emulate the instruction, 0 otherwise, or
  *           a negative value on error.
  */
-static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr,
-                              u32 error_code)
+static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr, u32 error_code,
+                            bool no_apf)
 {
        int write_fault = error_code & PFERR_WRITE_MASK;
        int user_fault = error_code & PFERR_USER_MASK;
@@ -569,7 +569,7 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr,
        mmu_seq = vcpu->kvm->mmu_notifier_seq;
        smp_rmb();
 
-       if (try_async_pf(vcpu, walker.gfn, addr, &pfn))
+       if (try_async_pf(vcpu, no_apf, walker.gfn, addr, &pfn))
                return 0;
 
        /* mmio */
index 3cd4d091c2f3bfe2bb3781089b9b1840f7c9fae9..71beb27597fd02aa9cd667e30e3f2e6345cd2023 100644 (file)
@@ -6138,6 +6138,20 @@ void kvm_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags)
 }
 EXPORT_SYMBOL_GPL(kvm_set_rflags);
 
+void kvm_arch_async_page_ready(struct kvm_vcpu *vcpu, struct kvm_async_pf *work)
+{
+       int r;
+
+       if (!vcpu->arch.mmu.direct_map || is_error_page(work->page))
+               return;
+
+       r = kvm_mmu_reload(vcpu);
+       if (unlikely(r))
+               return;
+
+       vcpu->arch.mmu.page_fault(vcpu, work->gva, 0, true);
+}
+
 static inline u32 kvm_async_pf_hash_fn(gfn_t gfn)
 {
        return hash_32(gfn & 0xffffffff, order_base_2(ASYNC_PF_PER_VCPU));
index 857d63431cb71ab6879f960f843147a7ed0f4e4d..e97eae965a4c030af72935d9959fcdbab567e6ad 100644 (file)
@@ -132,6 +132,8 @@ void kvm_check_async_pf_completion(struct kvm_vcpu *vcpu)
        list_del(&work->link);
        spin_unlock(&vcpu->async_pf.lock);
 
+       if (work->page)
+               kvm_arch_async_page_ready(vcpu, work);
        kvm_arch_async_page_present(vcpu, work);
 
        list_del(&work->queue);