All Virtuozzo development lists (kernel + QEMU)
 help / color / mirror / Atom feed
* [Devel] [PATCH hci-8.1] ms/KVM: x86: Fix lost EOI when unmasking a pending level IOAPIC pin
@ 2026-11-02 10:55 Denis V. Lunev
  2026-11-02 11:17 ` no-reply
  2026-11-02 16:07 ` Konstantin Khorenko
  0 siblings, 2 replies; 3+ messages in thread
From: Denis V. Lunev @ 2026-11-02 10:55 UTC (permalink / raw)
  Cc: devel

When the guest unmasks a level-triggered redirection entry whose line is
already asserted, ioapic_write_indirect() injects the pending interrupt
first and only then asks the destination vCPUs to rescan their
ioapic_handled_vectors and EOI exit bitmaps. If the same write also set
the vector or the trigger mode, a destination vCPU can take the interrupt
and EOI it before the rescan. A posted interrupt reaches a running vCPU
without a VM exit, and the EOI is then either virtualized without an exit
or dropped by kvm_ioapic_send_eoi() because the vector is not in
ioapic_handled_vectors yet. Remote IRR stays set and the pin delivers no
more interrupts until the guest reprograms it.

Linux programs the entry masked and unmasks it with a separate write, so
the vector is scanned before anything can be injected. Windows writes
the vector, the trigger mode and the mask bit in one go. A virtio balloon
on INTx whose line is already up when the driver connects its interrupt
then stops receiving interrupts for the rest of the boot, and the guest
ignores every later balloon target.

Make the scan request before servicing the pending IRR. The request
waits for the destination vCPUs to leave guest mode, and each of them
rescans the routes and reloads its EOI exit bitmap before it can enter
the guest and take the interrupt.

Fixes: c7c9c56ca26f ("x86, apicv: add virtual interrupt delivery support")
Fixes: 3bb345f387dd ("KVM: x86: store IOAPIC-handled vectors in each VCPU")
Link: https://lore.kernel.org/kvm/20261029-kvm-ioapic-eoi-v1-den@openvz.org/

https://virtuozzo.atlassian.net/browse/VSTOR-151727
Feature: fix ms/kvm
Signed-off-by: Denis V. Lunev <den@openvz.org>
---
Posted upstream, with a kvm-unit-tests reproducer in the same thread:
https://lore.kernel.org/kvm/20261029-kvm-ioapic-eoi-v1-den@openvz.org/
https://lore.kernel.org/kvm/20261029200214.1241130-1-den@openvz.org/

Tested on sqvm2-4061 (nested Intel, APICv) with kvm.ko and kvm-intel.ko
built out of tree from 6.12.0-211.52.1.22.9 plus this patch; ioapic.c is
the same in 22.14. The ioapic_eoi_race test lost 4587 of 5000 EOIs in
the single-write case on the stock modules and none with the patch; the
masked-write case lost none on either. x86/ioapic.flat passes, in-kernel
and split irqchip. Mainline 7.2.13 behaves the same, stock and patched.

 arch/x86/kvm/ioapic.c | 66 +++++++++++++++++++++----------------------
 1 file changed, 33 insertions(+), 33 deletions(-)

diff --git a/arch/x86/kvm/ioapic.c b/arch/x86/kvm/ioapic.c
index 2c2783296aed..546414dcf1df 100644
--- a/arch/x86/kvm/ioapic.c
+++ b/arch/x86/kvm/ioapic.c
@@ -388,39 +388,6 @@ static void ioapic_write_indirect(struct kvm_ioapic *ioapic, u32 val)
 		mask_after = e->fields.mask;
 		if (mask_before != mask_after)
 			kvm_fire_mask_notifiers(ioapic->kvm, KVM_IRQCHIP_IOAPIC, index, mask_after);
-		if (e->fields.trig_mode == IOAPIC_LEVEL_TRIG &&
-		    ioapic->irr & (1 << index) && !e->fields.mask && !e->fields.remote_irr) {
-			/*
-			 * Pending status in irr may be outdated: the IRQ line may have
-			 * already been deasserted by a device while the IRQ was masked.
-			 * This occurs, for instance, if the interrupt is handled in a
-			 * Linux guest as a oneshot interrupt (IRQF_ONESHOT). In this
-			 * case the guest acknowledges the interrupt to the device in
-			 * its threaded irq handler, i.e. after the EOI but before
-			 * unmasking, so at the time of unmasking the IRQ line is
-			 * already down but our pending irr bit is still set. In such
-			 * cases, injecting this pending interrupt to the guest is
-			 * buggy: the guest will receive an extra unwanted interrupt.
-			 *
-			 * So we need to check here if the IRQ is actually still pending.
-			 * As we are generally not able to probe the IRQ line status
-			 * directly, we do it through irqfd resampler. Namely, we clear
-			 * the pending status and notify the resampler that this interrupt
-			 * is done, without actually injecting it into the guest. If the
-			 * IRQ line is actually already deasserted, we are done. If it is
-			 * still asserted, a new interrupt will be shortly triggered
-			 * through irqfd and injected into the guest.
-			 *
-			 * If, however, it's not possible to resample (no irqfd resampler
-			 * registered for this irq), then unconditionally inject this
-			 * pending interrupt into the guest, so the guest will not miss
-			 * an interrupt, although may get an extra unwanted interrupt.
-			 */
-			if (kvm_notify_irqfd_resampler(ioapic->kvm, KVM_IRQCHIP_IOAPIC, index))
-				ioapic->irr &= ~(1 << index);
-			else
-				ioapic_service(ioapic, index, false);
-		}
 		if (e->fields.delivery_mode == APIC_DM_FIXED) {
 			struct kvm_lapic_irq irq;
 
@@ -455,6 +422,39 @@ static void ioapic_write_indirect(struct kvm_ioapic *ioapic, u32 val)
 		} else {
 			kvm_make_scan_ioapic_request(ioapic->kvm);
 		}
+		if (e->fields.trig_mode == IOAPIC_LEVEL_TRIG &&
+		    ioapic->irr & (1 << index) && !e->fields.mask && !e->fields.remote_irr) {
+			/*
+			 * Pending status in irr may be outdated: the IRQ line may have
+			 * already been deasserted by a device while the IRQ was masked.
+			 * This occurs, for instance, if the interrupt is handled in a
+			 * Linux guest as a oneshot interrupt (IRQF_ONESHOT). In this
+			 * case the guest acknowledges the interrupt to the device in
+			 * its threaded irq handler, i.e. after the EOI but before
+			 * unmasking, so at the time of unmasking the IRQ line is
+			 * already down but our pending irr bit is still set. In such
+			 * cases, injecting this pending interrupt to the guest is
+			 * buggy: the guest will receive an extra unwanted interrupt.
+			 *
+			 * So we need to check here if the IRQ is actually still pending.
+			 * As we are generally not able to probe the IRQ line status
+			 * directly, we do it through irqfd resampler. Namely, we clear
+			 * the pending status and notify the resampler that this interrupt
+			 * is done, without actually injecting it into the guest. If the
+			 * IRQ line is actually already deasserted, we are done. If it is
+			 * still asserted, a new interrupt will be shortly triggered
+			 * through irqfd and injected into the guest.
+			 *
+			 * If, however, it's not possible to resample (no irqfd resampler
+			 * registered for this irq), then unconditionally inject this
+			 * pending interrupt into the guest, so the guest will not miss
+			 * an interrupt, although may get an extra unwanted interrupt.
+			 */
+			if (kvm_notify_irqfd_resampler(ioapic->kvm, KVM_IRQCHIP_IOAPIC, index))
+				ioapic->irr &= ~(1 << index);
+			else
+				ioapic_service(ioapic, index, false);
+		}
 		break;
 	}
 }
-- 
2.53.0

_______________________________________________
Devel mailing list
Devel@openvz.org
https://lists.openvz.org/mailman/listinfo/devel

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [Devel] [PATCH hci-8.1] ms/KVM: x86: Fix lost EOI when unmasking a pending level IOAPIC pin
  2026-11-02 10:55 [Devel] [PATCH hci-8.1] ms/KVM: x86: Fix lost EOI when unmasking a pending level IOAPIC pin Denis V. Lunev
@ 2026-11-02 11:17 ` no-reply
  2026-11-02 16:07 ` Konstantin Khorenko
  1 sibling, 0 replies; 3+ messages in thread
From: no-reply @ 2026-11-02 11:17 UTC (permalink / raw)
  To: Denis V. Lunev; +Cc: devel

> When the guest unmasks a level-triggered redirection entry whose line is
> already asserted, ioapic_write_indirect() injects the pending interrupt
> first and only then asks the destination vCPUs to rescan their
> ioapic_handled_vectors and EOI exit bitmaps. If the same write also set
> the vector or the trigger mode, a destination vCPU can take the interrupt
> and EOI it before the rescan. A posted interrupt reaches a running vCPU
> without a VM exit, and the EOI is then either virtualized without an exit
> or dropped by kvm_ioapic_send_eoi() because the vector is not in
> ioapic_handled_vectors yet. Remote IRR stays set and the pin delivers no
> more interrupts until the guest reprograms it.
> 
> Linux programs the entry masked and unmasks it with a separate write, so
> the vector is scanned before anything can be injected. Windows writes
> the vector, the trigger mode and the mask bit in one go. A virtio balloon
> on INTx whose line is already up when the driver connects its interrupt
> then stops receiving interrupts for the rest of the boot, and the guest
> ignores every later balloon target.
> 
> Make the scan request before servicing the pending IRR. The request
> waits for the destination vCPUs to leave guest mode, and each of them
> rescans the routes and reloads its EOI exit bitmap before it can enter
> the guest and take the interrupt.
> 
> Fixes: c7c9c56ca26f ("x86, apicv: add virtual interrupt delivery support")
> Fixes: 3bb345f387dd ("KVM: x86: store IOAPIC-handled vectors in each VCPU")
> Link: https://lore.kernel.org/kvm/20261029-kvm-ioapic-eoi-v1-den@openvz.org/
> 
> https://virtuozzo.atlassian.net/browse/VSTOR-151727
> Feature: fix ms/kvm
> Signed-off-by: Denis V. Lunev <den@openvz.org>

Sashiko has reviewed this patch and found no issues. It looks great!

-- 
Sashiko AI review · https://sashiko.vzint.dev/#/patchset/20261102105510.3330185-1-den@openvz.org?part=1


_______________________________________________
Devel mailing list
Devel@openvz.org
https://lists.openvz.org/mailman/listinfo/devel

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [Devel] [PATCH hci-8.1] ms/KVM: x86: Fix lost EOI when unmasking a pending level IOAPIC pin
  2026-11-02 10:55 [Devel] [PATCH hci-8.1] ms/KVM: x86: Fix lost EOI when unmasking a pending level IOAPIC pin Denis V. Lunev
  2026-11-02 11:17 ` no-reply
@ 2026-11-02 16:07 ` Konstantin Khorenko
  1 sibling, 0 replies; 3+ messages in thread
From: Konstantin Khorenko @ 2026-11-02 16:07 UTC (permalink / raw)
  To: Denis V. Lunev; +Cc: devel

On Mon, 02 Nov 2026 11:55:05 +0100, Denis V. Lunev wrote:
> ms/KVM: x86: Fix lost EOI when unmasking a pending level IOAPIC pin

Applied to branch-rh10-6.12.0-211.52.1.22.x.vz10-ovz, will be released in rh10-6.12.0-211.52.1.22.16.vz10, thanks!

[1/1] ms/KVM: x86: Fix lost EOI when unmasking a pending level IOAPIC pin
      https://bitbucket.org/virtuozzocore/vzkernel.vzs/commits/5eb1b3d1ed8d

-- 
Konstantin Khorenko,
Virtuozzo Linux Kernel Team


_______________________________________________
Devel mailing list
Devel@openvz.org
https://lists.openvz.org/mailman/listinfo/devel

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-11-02 16:08 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-11-02 10:55 [Devel] [PATCH hci-8.1] ms/KVM: x86: Fix lost EOI when unmasking a pending level IOAPIC pin Denis V. Lunev
2026-11-02 11:17 ` no-reply
2026-11-02 16:07 ` Konstantin Khorenko

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.