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@xxxxxxxxxx> Reviewed-by: Nikita Leshenko <nikita.leshchenko@xxxxxxxxxx> Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@xxxxxxxxxx> --- arch/x86/kernel/irq.c | 1 + arch/x86/kvm/vmx.c | 9 ++++++--- 2 files changed, 7 insertions(+), 3 deletions(-) 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)); -- 1.9.1