⬢ DragonFlyBSD Kernel Audit
DF-5182 / fix.diff
← back to finding ↓ download raw
--- a/sys/dev/drm/include/linux/wait.h
+++ b/sys/dev/drm/include/linux/wait.h
@@ -122,13 +122,13 @@ void finish_wait(wait_queue_head_t *q, wait_queue_entry_t *wait);
 	prepare_to_wait(&wq, &tmp_wq, state);				\
 									\
 	while (1) {							\
 		__wait_event_prefix(&wq, flags);			\
 									\
+		tsleep_interlock(current, flags);			\
 		if (condition)						\
 			break;						\
 									\
-		tsleep_interlock(current, flags);			\
-									\
 		if ((timeout_jiffies) != 0) {				\
 			ret = tsleep(current, PINTERLOCKED|flags, "lwe", timeout_jiffies);	\
 		} else {						\
--- a/sys/dev/drm/include/linux/sched.h
+++ b/sys/dev/drm/include/linux/sched.h
@@ -240,8 +240,11 @@ wake_up_process(struct task_struct *tsk)
 	spin_lock(&tsk->kt_spin);
 	ostate = tsk->state;
 	tsk->state = TASK_RUNNING;
 	spin_unlock(&tsk->kt_spin);
-	if (ostate != TASK_RUNNING)
+	if (ostate != TASK_RUNNING) {
 		wakeup(tsk);
+		return 1;
+	}
 
-	return 1;	/* Always indicate the process was woken up */
+	return 0;	/* was already running: nothing was woken */
 }
 
 static inline int
--- a/sys/dev/drm/linux_wait.c
+++ b/sys/dev/drm/linux_wait.c
@@ -37,11 +37,12 @@ int
 autoremove_wake_function(wait_queue_entry_t *wait, unsigned mode, int sync, void *key)
 {
 	int ret = default_wake_function(wait, mode, sync, key);
 
-	/* Was the process woken up ? */
+	/* Only unlink the entry if a wakeup was actually delivered;
+	 * wake_up_process() returning 0 means the target was already
+	 * RUNNING and no wakeup() was issued. */
 	if (ret)
 		list_del_init(&wait->entry);
 
 	return ret;
 }