diff --git a/arch/x86/kvm/irq.h b/arch/x86/kvm/irq.h index 1a84ea31e7fd..eeaf527cecc4 100644 --- a/arch/x86/kvm/irq.h +++ b/arch/x86/kvm/irq.h @@ -118,6 +118,22 @@ int kvm_cpu_has_extint(struct kvm_vcpu *v); int kvm_cpu_get_extint(struct kvm_vcpu *v); int kvm_cpu_get_interrupt(struct kvm_vcpu *v); +static inline void kvm_warn_on_lost_irq(struct kvm_vcpu *vcpu) +{ + /* + * WARN if an IRQ was lost between detecting the IRQ and grabbing the + * IRQ for injection, unless it's possible the lost IRQ was due to one + * of the exceptional cases below. + * + * If the VM has an in-kernel PIC, the ExtINT handling that's routed + * through KVM's virtual PIC is tracked per-VM, not per-vCPU. If + * another vCPU grabs the IRQ, or deasserts the interrupt (which is + * level-triggered), then it's both expected and "fine" for an IRQ + * seemingly be "lost" from this vCPU's perspective. + */ + WARN_ON_ONCE(!pic_in_kernel(vcpu->kvm)); +} + void kvm_inject_pending_timer_irqs(struct kvm_vcpu *vcpu); void kvm_inject_apic_timer_irqs(struct kvm_vcpu *vcpu); void kvm_apic_nmi_wd_deliver(struct kvm_vcpu *vcpu); diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c index a9af4e9e6657..ed9dd03a1ddf 100644 --- a/arch/x86/kvm/vmx/nested.c +++ b/arch/x86/kvm/vmx/nested.c @@ -4467,8 +4467,10 @@ static int vmx_check_nested_events(struct kvm_vcpu *vcpu) } irq = kvm_apic_has_interrupt(vcpu); - if (WARN_ON_ONCE(irq < 0)) + if (unlikely(irq < 0)) { + kvm_warn_on_lost_irq(vcpu); goto no_vmexit; + } /* * If the IRQ is L2's PI notification vector, process posted diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index dfaf80efec4b..3be5024045da 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -7733,10 +7733,12 @@ static int kvm_check_and_inject_events(struct kvm_vcpu *vcpu, if (r) { int irq = kvm_cpu_get_interrupt(vcpu); - if (!WARN_ON_ONCE(irq == -1)) { + if (likely(irq != -1)) { kvm_queue_interrupt(vcpu, irq, false); kvm_x86_call(inject_irq)(vcpu, false); WARN_ON(kvm_x86_call(interrupt_allowed)(vcpu, true) < 0); + } else { + kvm_warn_on_lost_irq(vcpu); } } if (kvm_cpu_has_injectable_intr(vcpu))