DragonFlyBSD Kernel Audit
DF-0245 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/kern/kern_iosched.c b/sys/kern/kern_iosched.c
--- a/sys/kern/kern_iosched.c
+++ b/sys/kern/kern_iosched.c
@@ -87,7 +87,18 @@
 		/* be careful of interger overflows */
 		bytes = (int64_t)td->td_iosdata.iowbytes * delta / (hz * 10);
 		td->td_iosdata.iowbytes -= bytes;
-		ioscpu[gd->gd_cpuid].iowbytes -= bytes;
+		/*
+		 * DF-0245: td->td_iosdata.iowbytes migrates with the
+		 * thread, but ioscpu[] is per-cpu.  If the thread
+		 * accumulated weight on another cpu, this cpu's counter
+		 * may hold less than `bytes'; clamping prevents the
+		 * size_t subtraction from underflowing to SIZE_T_MAX and
+		 * wrecking the throttle factor.
+		 */
+		if (ioscpu[gd->gd_cpuid].iowbytes >= bytes)
+			ioscpu[gd->gd_cpuid].iowbytes -= bytes;
+		else
+			ioscpu[gd->gd_cpuid].iowbytes = 0;
 		iostotal -= bytes;
 	}
 
@@ -114,7 +125,10 @@
 
 	if ((bytes = td->td_iosdata.iowbytes) != 0) {
 		td->td_iosdata.iowbytes = 0;
-		ioscpu[gd->gd_cpuid].iowbytes -= bytes;
+		if (ioscpu[gd->gd_cpuid].iowbytes >= bytes)
+			ioscpu[gd->gd_cpuid].iowbytes -= bytes;
+		else
+			ioscpu[gd->gd_cpuid].iowbytes = 0;
 	}
 }