⬢ DragonFlyBSD Kernel Audit
DF-4918 / fix.diff
← back to finding ↓ download raw
--- 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);
 	}