vkernel - Fix lockup with [v]kernel due to missing ipiq signal
authorMatthew Dillon <dillon@apollo.backplane.com>
Thu, 28 Jul 2011 23:16:29 +0000 (16:16 -0700)
committerMatthew Dillon <dillon@apollo.backplane.com>
Thu, 28 Jul 2011 23:16:29 +0000 (16:16 -0700)
* If the target ipiq has nothing but passively queued entries the target
  cpu will normally just process the ipi's on the next clock interrupt.

  However, if the originating cpu is forced to live-loop waiting for the
  target to the drain the target may not be aware that it needs to drain
  ASAP.

* The fix is for the originating cpu to ensure that an ipi interrupt is
  sent to the target cpu before live looping.

* This appears to primarily effect vkernels.

Reported-by: ftigeot, tuxillo
sys/kern/lwkt_ipiq.c

index a4416e0..34e206b 100644 (file)
@@ -179,6 +179,10 @@ lwkt_send_ipiq3(globaldata_t target, ipifunc3_t func, void *arg1, int arg2)
     /*
      * Do not allow the FIFO to become full.  Interrupts must be physically
      * enabled while we liveloop to avoid deadlocking the APIC.
+     *
+     * The target ipiq may have gotten filled up due to passive IPIs and thus
+     * not be aware that its queue is too full, so be sure to issue an
+     * ipiq interrupt to the target cpu.
      */
     if (ip->ip_windex - ip->ip_rindex > MAXCPUFIFO / 2) {
 #if defined(__i386__)
@@ -193,6 +197,7 @@ lwkt_send_ipiq3(globaldata_t target, ipifunc3_t func, void *arg1, int arg2)
        }
        cpu_enable_intr();
        ++ipiq_fifofull;
+       cpu_send_ipiq(target->gd_cpuid);
        DEBUG_PUSH_INFO("send_ipiq3");
        while (ip->ip_windex - ip->ip_rindex > MAXCPUFIFO / 4) {
            KKASSERT(ip->ip_windex - ip->ip_rindex != MAXCPUFIFO - 1);
@@ -286,6 +291,7 @@ lwkt_send_ipiq3_passive(globaldata_t target, ipifunc3_t func,
        }
        cpu_enable_intr();
        ++ipiq_fifofull;
+       cpu_send_ipiq(target->gd_cpuid);
        DEBUG_PUSH_INFO("send_ipiq3_passive");
        while (ip->ip_windex - ip->ip_rindex > MAXCPUFIFO / 4) {
            KKASSERT(ip->ip_windex - ip->ip_rindex != MAXCPUFIFO - 1);