DragonFlyBSD Kernel Audit
DF-2879 / fix.diff
← back to finding ↓ download raw
--- a/sys/vm/vm_swap.c
+++ b/sys/vm/vm_swap.c
@@ -362,8 +362,19 @@
 	 * DEV_BSIZE'd.   aligned_nblks is used to calculate the
 	 * size of the swap bitmap, taking into account the stripe size.
 	 */
-	aligned_nblks = (swblk_t)((nblks + SWB_DMMASK) &
-				  ~(u_swblk_t)SWB_DMMASK);
+	/*
+	 * DO NOT round up to a SWB_DMMAX multiple.  Rounding up registers
+	 * up to SWB_DMMASK (63) swap pages per device that do not exist on
+	 * the device: the free-loop below hands the entire last stripe,
+	 * including the phantom tail beyond the real device end, to the
+	 * blist as allocatable swap.  Any pageout the pager directs at a
+	 * phantom block is rejected by the disk layer (EINVAL from
+	 * dscheck), wedging the pageout daemon in an unbounded
+	 * error-retry loop.  Use the real (page-truncated) block count;
+	 * the min() in both this free-loop and swapoff_one()'s fill-loop
+	 * already clips the final partial stripe to the real device size.
+	 */
+	aligned_nblks = (swblk_t)nblks;
 	sp->sw_nblks = aligned_nblks;
 
 	if (aligned_nblks * nswdev > nswap)