DragonFlyBSD Kernel Audit
DF-1979 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/dev/drm/include/linux/workqueue.h b/sys/dev/drm/include/linux/workqueue.h
--- a/sys/dev/drm/include/linux/workqueue.h
+++ b/sys/dev/drm/include/linux/workqueue.h
@@ -60,6 +60,7 @@
 struct workqueue_struct {
 	bool	is_draining;
 	int	num_workers;
+	struct lock		queue_lock;	/* serializes cross-CPU queue_work */
 	struct	workqueue_worker (*workers)[];
 };
 
--- a/sys/dev/drm/linux_workqueue.c
+++ b/sys/dev/drm/linux_workqueue.c
@@ -122,9 +122,11 @@
 	struct workqueue_worker *worker;
 	int ret = false;
 
+	lockmgr(&wq->queue_lock, LK_EXCLUSIVE);
+
 	/* XXX: should we block instead ? */
 	if (wq->is_draining)
-		return false;
+		goto out;
 
 	if (wq->num_workers > 1)
 		worker = &(*wq->workers)[mycpuid];
@@ -144,6 +146,8 @@
 		ret = true;
 	}
 	lockmgr(&worker->worker_lock, LK_RELEASE);
+out:
+	lockmgr(&wq->queue_lock, LK_RELEASE);
 
 	return ret;
 }
@@ -201,6 +205,8 @@
 
 	wq = kmalloc(sizeof(*wq), M_DRM, M_WAITOK | M_ZERO);
 
+	lockinit(&wq->queue_lock, "wqql", 0, 0);
+
 	if (flags & WQ_HIGHPRI)
 		priority = TDPRI_INT_SUPPORT;
 	else