[PATCH 1/2] KVM: x86: ioapic: Update state only after successful delivery
Hao Zhang <[email protected]>
| Newsgroups | org.kernel.vger.kvm |
|---|---|
| Message-ID | <[email protected]> |
From: Hao Zhang <[email protected]> The I/O APIC tracks delivered interrupts in state that is later used to decide whether an interrupt is still pending or blocked waiting for an EOI. For level-triggered interrupts, remote_irr means that a local APIC accepted the interrupt and that the I/O APIC must wait for the corresponding EOI before delivering the interrupt again. For edge-triggered interrupts, irr_delivered is used to hide delivered interrupts from KVM_GET_IRQCHIP so that userspace does not reinject an interrupt that has already left the I/O APIC. But ioapic_service() currently updates that state before or without checking that interrupt delivery actually succeeded. kvm_irq_delivery_to_apic() can return -1 when no destination is found. Treating failed delivery as success can either leave a level-triggered pin blocked forever waiting for an EOI that will never be generated, or cause KVM_GET_IRQCHIP to drop an undelivered edge-triggered interrupt from the saved IRR state. Update I/O APIC delivery state only when the delivery result is positive, i.e. when at least one local APIC accepted the interrupt. Fixes: 4925663a079c ("KVM: Report IRQ injection status to userspace.") Fixes: 5bda6eed2e36 ("KVM: ioapic: Record edge-triggered interrupts delivery status") Signed-off-by: Hao Zhang <[email protected]> --- Changes in v2: - Address Kai Huang's review by deferring both remote_irr and irr_delivered updates until interrupt delivery succeeds. - Extend the selftest to cover failed edge-triggered delivery and verify that the interrupt remains pending in IRR. Link to v1: https://lore.kernel.org/all/[email protected]/ arch/x86/kvm/ioapic.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/arch/x86/kvm/ioapic.c b/arch/x86/kvm/ioapic.c index 757667fb2bfa..540e5665fbe4 100644 --- a/arch/x86/kvm/ioapic.c +++ b/arch/x86/kvm/ioapic.c @@ -474,9 +474,6 @@ static int ioapic_service(struct kvm_ioapic *ioapic, int irq, bool line_status) irqe.shorthand = APIC_DEST_NOSHORT; irqe.msi_redir_hint = false; - if (irqe.trig_mode == IOAPIC_EDGE_TRIG) - ioapic->irr_delivered |= 1 << irq; - if (irq == RTC_GSI && line_status) { /* * pending_eoi cannot ever become negative (see @@ -491,8 +488,12 @@ static int ioapic_service(struct kvm_ioapic *ioapic, int irq, bool line_status) } else ret = kvm_irq_delivery_to_apic(ioapic->kvm, NULL, &irqe); - if (ret && irqe.trig_mode == IOAPIC_LEVEL_TRIG) - entry->fields.remote_irr = 1; + if (ret > 0) { + if (irqe.trig_mode == IOAPIC_EDGE_TRIG) + ioapic->irr_delivered |= 1 << irq; + else if (irqe.trig_mode == IOAPIC_LEVEL_TRIG) + entry->fields.remote_irr = 1; + } return ret; } base-commit: c21bb4193868a8de71fc4693fa741e195fdf5d86 -- 2.15.0