vmd(8): fix an interrupt storm in ns8250.
authordv <dv@openbsd.org>
Mon, 30 Jan 2023 21:43:12 +0000 (21:43 +0000)
committerdv <dv@openbsd.org>
Mon, 30 Jan 2023 21:43:12 +0000 (21:43 +0000)
On slower hosts, such as those in a nested virtualization scenario
of OpenBSD guest inside OpenBSD atop Linux KVM, ns8250 can cause a
race between the kevent firing and the vcpu being kicked by an
assert/deassert of the irq.

The end user experiences a "stuck" serial console and the host will
see a vmd process peg the cpu.

This change only toggles the irq if we were in a position of being
ready to receive data on the device so while the kevent might
continuously fire, the vcpu will not be kicked repeatedly.

OK mlarkin@

usr.sbin/vmd/ns8250.c

index dbb6568..f9d1433 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: ns8250.c,v 1.34 2022/12/28 21:30:19 jmc Exp $ */
+/* $OpenBSD: ns8250.c,v 1.35 2023/01/30 21:43:12 dv Exp $ */
 /*
  * Copyright (c) 2016 Mike Larkin <mlarkin@openbsd.org>
  *
@@ -153,14 +153,15 @@ com_rcv_event(int fd, short kind, void *arg)
                return;
        }
 
-       if ((com1_dev.regs.lsr & LSR_RXRDY) == 0)
+       if ((com1_dev.regs.lsr & LSR_RXRDY) == 0) {
                com_rcv(&com1_dev, (uintptr_t)arg, 0);
 
-       /* If pending interrupt, inject */
-       if ((com1_dev.regs.iir & IIR_NOPEND) == 0) {
-               /* XXX: vcpu_id */
-               vcpu_assert_pic_irq((uintptr_t)arg, 0, com1_dev.irq);
-               vcpu_deassert_pic_irq((uintptr_t)arg, 0, com1_dev.irq);
+               /* If pending interrupt, inject */
+               if ((com1_dev.regs.iir & IIR_NOPEND) == 0) {
+                       /* XXX: vcpu_id */
+                       vcpu_assert_pic_irq((uintptr_t)arg, 0, com1_dev.irq);
+                       vcpu_deassert_pic_irq((uintptr_t)arg, 0, com1_dev.irq);
+               }
        }
 
        mutex_unlock(&com1_dev.mutex);