⬢ DragonFlyBSD Kernel Audit
DF-5235 / fix.diff
← back to finding ↓ download raw
--- a/sys/dev/drm/include/linux/completion.h
+++ b/sys/dev/drm/include/linux/completion.h
@@ -80,14 +80,23 @@
 			      unsigned long timeout, int flags)
 {
 	int start_jiffies, elapsed_jiffies, remaining_jiffies;
+	int timo;
 	bool timeout_expired = false, awakened = false;
 	long ret = 1;
 
+	/*
+	 * lksleep()'s timo is an int.  MAX_SCHEDULE_TIMEOUT (LONG_MAX) does
+	 * not fit and truncates to -1, which _callout_setup_quick() clamps
+	 * to the *next* tick -- turning every "infinite" completion wait
+	 * into a ~1-tick wait.  Convert exactly like schedule_timeout() in
+	 * linux/sched.h does: 0 means "no timeout" for tsleep/lksleep.
+	 */
+	timo = (timeout >= INT_MAX) ? 0 : (int)timeout;
 	start_jiffies = ticks;
 
 	lockmgr(&c->wait.lock, LK_EXCLUSIVE);
 	while (c->done == 0 && !timeout_expired) {
-		ret = lksleep(&c->wait, &c->wait.lock, flags, "lwfcg", timeout);
+		ret = lksleep(&c->wait, &c->wait.lock, flags, "lwfcg", timo);
 		switch(ret) {
 		case EWOULDBLOCK:
 			timeout_expired = true;