diff mbox

[v2,5/5] KVM: nVMX: Wake halted L2 on nested posted-interrupt

Message ID 1512461786-6465-6-git-send-email-liran.alon@oracle.com (mailing list archive)
State New, archived
Headers show

Commit Message

Liran Alon Dec. 5, 2017, 8:16 a.m. UTC
If L1 don't intercept L2 HLT (doesn't set CPU_BASED_HLT_EXITING),
then when L2 executes HLT instruction, KVM will block vCPU from
further execution (just like what happens when L1 executes HLT).

Therefore, when some CPU sends nested-posted-interrupts to L2 there
are 2 important cases to handle:

1. vmx_deliver_nested_posted_interrupt() note that
vcpu->mode != IN_GUEST_MODE and therefore doesn't send a physical IPI.
Because the dest vCPU could be blocked by HLT, we should kick it.

2. vmx_deliver_nested_posted_interrupt() sees that
vcpu->mode == IN_GUEST_MODE and therefore sends a physical IPI but
before it sends the physical IPI, the dest CPU executing L2 executes
HLT which caused the dest vCPU to be blocked. Therefore, the physical
IPI will be received at host and it's handler should make sure to
unblock the vCPU.

Fixes: 705699a13994 ("KVM: nVMX: Enable nested posted interrupt
processing")

Signed-off-by: Liran Alon <liran.alon@oracle.com>
Reviewed-by: Nikita Leshenko <nikita.leshchenko@oracle.com>
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
---
 arch/x86/kernel/irq.c | 1 +
 arch/x86/kvm/vmx.c    | 9 ++++++---
 2 files changed, 7 insertions(+), 3 deletions(-)
diff mbox

Patch

diff --git a/arch/x86/kernel/irq.c b/arch/x86/kernel/irq.c
index 49cfd9fe7589..48c5e4a49279 100644
--- a/arch/x86/kernel/irq.c
+++ b/arch/x86/kernel/irq.c
@@ -326,6 +326,7 @@  __visible void smp_kvm_posted_intr_nested_ipi(struct pt_regs *regs)
 
 	entering_ack_irq();
 	inc_irq_stat(kvm_posted_intr_nested_ipis);
+	kvm_posted_intr_wakeup_handler();
 	exiting_irq();
 	set_irq_regs(old_regs);
 }
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 517822f94158..dcbc4ce5a32a 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -5082,7 +5082,8 @@  static int vmx_deliver_nested_posted_interrupt(struct kvm_vcpu *vcpu,
 	if (is_guest_mode(vcpu) &&
 	    vector == vmx->nested.posted_intr_nv) {
 		/* the PIR and ON have been set by L1. */
-		kvm_vcpu_trigger_posted_interrupt(vcpu, true);
+		if (!kvm_vcpu_trigger_posted_interrupt(vcpu, true))
+			kvm_vcpu_kick(vcpu);
 		return 0;
 	}
 	return -1;
@@ -6680,9 +6681,11 @@  static void wakeup_handler(void)
 	spin_lock(&per_cpu(blocked_vcpu_on_cpu_lock, cpu));
 	list_for_each_entry(vcpu, &per_cpu(blocked_vcpu_on_cpu, cpu),
 			blocked_vcpu_list) {
-		struct pi_desc *pi_desc = vcpu_to_pi_desc(vcpu);
+		struct vcpu_vmx *vmx = to_vmx(vcpu);
 
-		if (pi_test_on(pi_desc) == 1)
+		if ((pi_test_on(&vmx->pi_desc) == 1) ||
+		    (is_guest_mode(vcpu) && vmx->nested.pi_desc &&
+		     (pi_test_on(vmx->nested.pi_desc) == 1)))
 			kvm_vcpu_kick(vcpu);
 	}
 	spin_unlock(&per_cpu(blocked_vcpu_on_cpu_lock, cpu));