--- a/sys/dev/drm/linux_workqueue.c +++ b/sys/dev/drm/linux_workqueue.c @@ -275,8 +275,17 @@ lockmgr(&worker->worker_lock, LK_EXCLUSIVE); while (!STAILQ_EMPTY(&worker->ws_list_head)) { - /* XXX: introduces latency */ - tsleep(&drain_workqueue, 0, "wkdrain", 1); + /* + * DF-4918: tsleep() does not release held locks. + * Sleeping with worker_lock held starves the very + * worker that must drain this queue (it needs the + * lock to dequeue, process_all_work) and turns + * drain_workqueue() into a permanent deadlock. + * lksleep() releases the lock while sleeping and + * reacquires it on return. (XXX: still latency) + */ + lksleep(&drain_workqueue, &worker->worker_lock, 0, + "wkdrain", 1); } lockmgr(&worker->worker_lock, LK_RELEASE); }