In the current inject_page_fault path KVM only checks if there is another PF
pending and injects a DF then. But it has to check for a pendig DF too to
detect a shutdown condition in the VCPU. If this is not detected the VCPU goes
to a PF -> DF -> PF loop when it should triple fault. This patch detects this
condition and handles it with an KVM_SHUTDOWN exit to userspace. As a side
effect it fixes the following warning when trying to reboot a SMP guest on SVM:

--------------------------<snip>---------------------------------------
kvm: inject_page_fault: double fault 0x3f72
WARNING: at /home/jroedel/src/kvm/kvm-userspace/kernel/x86.c:171 
kvm_queue_exception_e()
Pid: 12088, comm: qemu-system-x86 Not tainted 2.6.24-rc8 #1

Call Trace:
 [<ffffffff88033328>] :kvm:kvm_queue_exception_e+0x78/0x80
 [<ffffffff8803995c>] :kvm:paging64_page_fault+0xec/0x510
 [<ffffffff8020a0d2>] __switch_to+0x42/0x310
 [<ffffffff805f8785>] _spin_unlock_irq+0x15/0x40
 [<ffffffff80233f1d>] __dequeue_entity+0x3d/0x50
 [<ffffffff8020a0d2>] __switch_to+0x42/0x310
 [<ffffffff80238dc7>] finish_task_switch+0x57/0xb0
 [<ffffffff805f64f0>] thread_return+0x5b/0x53b
 [<ffffffff88038679>] :kvm:kvm_mmu_page_fault+0x19/0x90
 [<ffffffff880351f7>] :kvm:kvm_arch_vcpu_ioctl_run+0x167/0x6e0
 [<ffffffff88030e81>] :kvm:kvm_vcpu_ioctl+0x351/0x360
 [<ffffffff80281d54>] find_extend_vma+0x24/0x80
 [<ffffffff8025f153>] get_futex_key+0x53/0x160
 [<ffffffff80399771>] __up_read+0x21/0xb0
 [<ffffffff805f8746>] _spin_unlock_irqrestore+0x16/0x40
 [<ffffffff8025fb6f>] futex_wake+0xcf/0xf0
 [<ffffffff80260f9b>] do_futex+0x66b/0xbf0
 [<ffffffff8026e1cb>] find_get_pages_tag+0x8b/0xb0
 [<ffffffff8024abd9>] __dequeue_signal+0x19/0x1c0
 [<ffffffff8024a67e>] recalc_sigpending+0xe/0x40
 [<ffffffff8024c10d>] dequeue_signal+0x5d/0x160
 [<ffffffff805f8785>] _spin_unlock_irq+0x15/0x40
 [<ffffffff8024d502>] sys_rt_sigtimedwait+0x2e2/0x2f0
 [<ffffffff802a58df>] do_ioctl+0x2f/0xa0
 [<ffffffff802a59c4>] vfs_ioctl+0x74/0x2d0
 [<ffffffff802a5c69>] sys_ioctl+0x49/0x80
 [<ffffffff8020bcfe>] system_call+0x7e/0x83
--------------------------<snip>---------------------------------------

Signed-off-by: Joerg Roedel <[EMAIL PROTECTED]>
---
 arch/x86/kvm/mmu.c         |    9 +++++++--
 arch/x86/kvm/paging_tmpl.h |   10 ++++++----
 arch/x86/kvm/x86.c         |   21 ++++++++++++++-------
 include/asm-x86/kvm_host.h |    2 +-
 4 files changed, 28 insertions(+), 14 deletions(-)

diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c
index 5c0f0af..2906ee5 100644
--- a/arch/x86/kvm/mmu.c
+++ b/arch/x86/kvm/mmu.c
@@ -1394,11 +1394,11 @@ static void paging_new_cr3(struct kvm_vcpu *vcpu)
        mmu_free_roots(vcpu);
 }
 
-static void inject_page_fault(struct kvm_vcpu *vcpu,
+static bool inject_page_fault(struct kvm_vcpu *vcpu,
                              u64 addr,
                              u32 err_code)
 {
-       kvm_inject_page_fault(vcpu, addr, err_code);
+       return kvm_inject_page_fault(vcpu, addr, err_code);
 }
 
 static void paging_free(struct kvm_vcpu *vcpu)
@@ -1815,6 +1815,11 @@ int kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gva_t cr2, 
u32 error_code)
                goto out;
        }
 
+       if (r == 2) {
+               vcpu->run->exit_reason = KVM_EXIT_SHUTDOWN;
+               return 0;
+       }
+
        r = mmu_topup_memory_caches(vcpu);
        if (r)
                goto out;
diff --git a/arch/x86/kvm/paging_tmpl.h b/arch/x86/kvm/paging_tmpl.h
index 1af0ceb..01708b7 100644
--- a/arch/x86/kvm/paging_tmpl.h
+++ b/arch/x86/kvm/paging_tmpl.h
@@ -366,8 +366,9 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,
  *   - normal guest page fault due to the guest pte marked not present, not
  *     writable, or not executable
  *
- *  Returns: 1 if we need to emulate the instruction, 0 otherwise, or
- *           a negative value on error.
+ *  Returns: 2 if the vcpu triple faulted
+ *          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)
@@ -381,6 +382,7 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t 
addr,
        int r;
        struct page *page;
        int largepage = 0;
+       bool injected;
 
        pgprintk("%s: addr %lx err %x\n", __FUNCTION__, addr, error_code);
        kvm_mmu_audit(vcpu, "pre page fault");
@@ -401,10 +403,10 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t 
addr,
         */
        if (!r) {
                pgprintk("%s: guest page fault\n", __FUNCTION__);
-               inject_page_fault(vcpu, addr, walker.error_code);
+               injected = inject_page_fault(vcpu, addr, walker.error_code);
                vcpu->arch.last_pt_write_count = 0; /* reset fork detector */
                up_read(&vcpu->kvm->slots_lock);
-               return 0;
+               return injected ? 0 : 2;
        }
 
        down_read(&current->mm->mmap_sem);
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index e1aa6c9..67b9f10 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -151,19 +151,26 @@ void kvm_queue_exception(struct kvm_vcpu *vcpu, unsigned 
nr)
 }
 EXPORT_SYMBOL_GPL(kvm_queue_exception);
 
-void kvm_inject_page_fault(struct kvm_vcpu *vcpu, unsigned long addr,
+bool kvm_inject_page_fault(struct kvm_vcpu *vcpu, unsigned long addr,
                           u32 error_code)
 {
        ++vcpu->stat.pf_guest;
-       if (vcpu->arch.exception.pending && vcpu->arch.exception.nr == 
PF_VECTOR) {
-               printk(KERN_DEBUG "kvm: inject_page_fault:"
-                      " double fault 0x%lx\n", addr);
-               vcpu->arch.exception.nr = DF_VECTOR;
-               vcpu->arch.exception.error_code = 0;
-               return;
+       if (vcpu->arch.exception.pending) {
+               if (vcpu->arch.exception.nr == PF_VECTOR) {
+                       printk(KERN_DEBUG "kvm: inject_page_fault:"
+                                       " double fault 0x%lx\n", addr);
+                       vcpu->arch.exception.nr = DF_VECTOR;
+                       vcpu->arch.exception.error_code = 0;
+                       return true;
+               } else if (vcpu->arch.exception.nr == DF_VECTOR) {
+                       /* triple fault,-> exit to userspace */
+                       return false;
+               }
        }
+
        vcpu->arch.cr2 = addr;
        kvm_queue_exception_e(vcpu, PF_VECTOR, error_code);
+       return true;
 }
 
 void kvm_queue_exception_e(struct kvm_vcpu *vcpu, unsigned nr, u32 error_code)
diff --git a/include/asm-x86/kvm_host.h b/include/asm-x86/kvm_host.h
index 024b57c..3d73df0 100644
--- a/include/asm-x86/kvm_host.h
+++ b/include/asm-x86/kvm_host.h
@@ -482,7 +482,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 
data);
 
 void kvm_queue_exception(struct kvm_vcpu *vcpu, unsigned nr);
 void kvm_queue_exception_e(struct kvm_vcpu *vcpu, unsigned nr, u32 error_code);
-void kvm_inject_page_fault(struct kvm_vcpu *vcpu, unsigned long cr2,
+bool kvm_inject_page_fault(struct kvm_vcpu *vcpu, unsigned long cr2,
                           u32 error_code);
 
 void fx_init(struct kvm_vcpu *vcpu);
-- 
1.5.3.7




-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2008.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
_______________________________________________
kvm-devel mailing list
kvm-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/kvm-devel

Reply via email to