⬢ DragonFlyBSD Kernel Audit
DF-4063 / fix.diff
← back to finding ↓ download raw
--- a/sys/dev/disk/fd/fd.c
+++ b/sys/dev/disk/fd/fd.c
@@ -2275,16 +2275,21 @@
 	/* now do the format */
 	dev_dstrategy(dev, &bp->b_bio1);
 
-	/* ...and wait for it to complete */
-	rv = biowait_timeout(&bp->b_bio1, "fdform", 20 * hz);
-	if (rv == EWOULDBLOCK) {
-		/* timed out */
-		rv = EIO;
-#if 0
-		device_unbusy(fd->dev);
-#endif
-		biodone(&bp->b_bio1);
-	}
+	/*
+	 * ...and wait for it to complete.  The controller state machine
+	 * always completes every buffer it dequeues (progress is bounded
+	 * by fd_iotimeout and retrier(), and parked states are kicked by
+	 * fd_turnoff every 4 s), and the bio stays linked in
+	 * fdc->bio_queue and owned by the driver until then.  It is NOT
+	 * safe to biodone() and relpbuf() the buffer early just because
+	 * we got tired of waiting: the driver would later double-complete
+	 * the bio and the recycled pbuf would be corrupted under it
+	 * (double TAILQ insertion of the same bio -> queue corruption).
+	 *
+	 * DF-4063: the old 20 s biowait_timeout + manual biodone() did
+	 * exactly that and reliably panicked the kernel.
+	 */
+	rv = biowait(&bp->b_bio1, "fdform");
 	if (bp->b_flags & B_ERROR)
 		rv = bp->b_error;
 	/*