DF-2329 / fix.diff
--- a/sys/bus/ppbus/ppbconf.c +++ b/sys/bus/ppbus/ppbconf.c @@ -484,14 +484,26 @@ while (!error) { crit_enter(); if (ppb->ppb_owner) { + /* + * DF-2329: ppb_release_bus's wakeup(ppb) can land + * between the crit_exit() and the tsleep() -- a lost + * wakeup that parks the requester forever + * (uninterruptible with PPB_WAIT|PPB_NOINTR). + * Interlock the sleep with the crit section (the + * same tsleep_interlock/PINTERLOCKED pattern CAM's + * sgread uses). + */ + tsleep_interlock(ppb, PCATCH); crit_exit(); switch (how) { case (PPB_WAIT | PPB_INTR): - error = tsleep(ppb, PCATCH, "ppbreq", 0); + error = tsleep(ppb, + PCATCH | PINTERLOCKED, "ppbreq", 0); break; case (PPB_WAIT | PPB_NOINTR): - error = tsleep(ppb, 0, "ppbreq", 0); + error = tsleep(ppb, PINTERLOCKED, + "ppbreq", 0); break; default: |