DF-5532 / fix.diff
--- a/sys/bus/u4b/usb_process.c +++ b/sys/bus/u4b/usb_process.c @@ -57,7 +57,7 @@ static int usb_pcount; #define USB_THREAD_CREATE(f, s, p, ...) \ kthread_create((f), (s), (p), __VA_ARGS__) -#define USB_THREAD_SUSPEND_CHECK() kthread_suspend_check(curproc) +#define USB_THREAD_SUSPEND_CHECK() kproc_suspend_loop() #define USB_THREAD_SUSPEND(p) suspend_kproc(p,0) #define USB_THREAD_EXIT(err) kthread_exit() @@ -97,6 +97,20 @@ while (1) { + /* + * DF-5533: honour suspend_kproc() requests so that + * usb_proc_drain()'s cold-boot branch can complete. + * The bus lock must be dropped while parking: the + * suspender sleeps until we acknowledge and then needs + * to re-acquire the lock itself, so parking while + * holding it deadlocks both threads. + */ + if (curthread->td_mpflags & TDF_MP_STOPREQ) { + lockmgr(up->up_lock, LK_RELEASE); + USB_THREAD_SUSPEND_CHECK(); + lockmgr(up->up_lock, LK_EXCLUSIVE); + } + if (up->up_gone) break; @@ -155,6 +169,18 @@ /* nothing changed */ TAILQ_REMOVE(&up->up_qhead, pm, pm_qentry); pm->pm_qentry.tqe_prev = NULL; + /* + * DF-5532: a completed message must be + * able to release usb_proc_mwait() waiters + * even when the queue never becomes empty. + * Previously the only wakeup was the + * empty-queue transition below, so any + * continuously refilled queue starved + * waiters whose messages had long + * completed. + */ + if (up->up_dsleep) + cv_broadcast(&up->up_drain); } DPRINTF("Message pm=%p (leave)\n", pm); @@ -433,7 +459,16 @@ /* Check if we are still cold booted */ if (cold) { + /* + * DF-5533: suspend_kproc() sleeps until the + * target thread acknowledges the stop request, + * so the bus lock must be dropped while + * waiting, else the target can never run its + * suspend check and both threads deadlock. + */ + lockmgr(up->up_lock, LK_RELEASE); USB_THREAD_SUSPEND(up->up_ptr); + lockmgr(up->up_lock, LK_EXCLUSIVE); kprintf("WARNING: A USB process has " "been left suspended\n"); break; |