From: Hao Zhang irr_delivered hides delivered edge interrupts from KVM_GET_IRQCHIP. The interrupt remains in IRR until the guest deasserts the line. The guest can reprogram an IOAPIC RTE from edge to level via MMIO. If an edge interrupt was delivered before the trigger mode change, a stale irr_delivered bit can incorrectly mask a subsequent pending level interrupt from KVM_GET_IRQCHIP. That can cause userspace to migrate the VM without a pending level interrupt that is still present in KVM's in-kernel IOAPIC. Clear irr_delivered when the RTE is configured for level-triggered interrupts. Fixes: 5bda6eed2e36 ("KVM: ioapic: Record edge-triggered interrupts delivery status") Signed-off-by: Hao Zhang --- arch/x86/kvm/ioapic.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/arch/x86/kvm/ioapic.c b/arch/x86/kvm/ioapic.c index 676effd674f9..81db025d2ac9 100644 --- a/arch/x86/kvm/ioapic.c +++ b/arch/x86/kvm/ioapic.c @@ -377,8 +377,17 @@ static void ioapic_write_indirect(struct kvm_ioapic *ioapic, u32 val) * as edge-triggered. This behavior is used to simulate an * explicit EOI on IOAPICs that don't have the EOI register. */ - if (e->fields.trig_mode == IOAPIC_EDGE_TRIG) + if (e->fields.trig_mode == IOAPIC_EDGE_TRIG) { e->fields.remote_irr = 0; + } else { + /* + * irr_delivered tracks edge-triggered interrupts that + * have already been delivered. Clear stale edge-triggered + * delivery state when the entry is configured for + * level-triggered interrupts. + */ + ioapic->irr_delivered &= ~(1 << index); + } mask_after = e->fields.mask; if (mask_before != mask_after) -- 2.15.0