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(¤t->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