⬢ DragonFlyBSD Kernel Audit
DF-5058 / fix.diff
← back to finding ↓ download raw
--- a/sys/dev/raid/mlx/mlx.c
+++ b/sys/dev/raid/mlx/mlx.c
@@ -684,6 +684,14 @@
 {
     debug_called(1);
 
+    /* DF-5058: once declared wedged, fail new arrivals immediately. */
+    if (sc->mlx_stall_ticks >= 60) {
+	bio->bio_buf->b_flags |= B_ERROR;
+	bio->bio_buf->b_error = ETIMEDOUT;
+	biodone(bio);
+	return(0);
+    }
+
     crit_enter();
     bioqdisksort(&sc->mlx_bioq, bio);
     sc->mlx_waitbufs++;
@@ -1037,7 +1045,37 @@
     mlx_enquire(sc, MLX_CMD_REBUILDSTAT, sizeof(struct mlx_rebuild_stat), mlx_periodic_rebuild);
 
     /* deal with possibly-missed interrupts and timed-out commands */
-    mlx_done(sc);
+    if (mlx_done(sc) != 0)
+	sc->mlx_stall_ticks = 0;	/* DF-5058: progress made */
+
+    /*
+     * DF-5058: bios park forever on mlx_bioq once the controller stops
+     * delivering completions (all command slots stuck BUSY; mc_timeout
+     * is never enforced).  If work has been pending continuously for 60
+     * seconds with zero completions, declare the controller wedged and
+     * fail everything queued so issuers become killable and the queue
+     * cannot grow without bound.
+     */
+    if (sc->mlx_waitbufs == 0) {
+	sc->mlx_stall_ticks = 0;
+    } else if (++sc->mlx_stall_ticks >= 60) {
+	struct bio *bio;
+
+	device_printf(sc->mlx_dev,
+	    "no completion progress in 60s, failing queued I/O\n");
+	crit_enter();
+	while ((bio = bioq_first(&sc->mlx_bioq)) != NULL) {
+	    bioq_remove(&sc->mlx_bioq, bio);
+	    sc->mlx_waitbufs--;
+	    crit_exit();
+	    bio->bio_buf->b_flags |= B_ERROR;
+	    bio->bio_buf->b_error = ETIMEDOUT;
+	    biodone(bio);
+	    crit_enter();
+	}
+	crit_exit();
+	sc->mlx_stall_ticks = 60;	/* keep failing new arrivals */
+    }
 
     /* reschedule another poll next second or so */
     callout_reset(&sc->mlx_timeout, hz, mlx_periodic, sc);
--- a/sys/dev/raid/mlx/mlxvar.h
+++ b/sys/dev/raid/mlx/mlxvar.h
@@ -137,6 +137,7 @@
     struct mlx_sysdrive	mlx_sysdrive[MLX_MAXDRIVES];	/* system drives */
     mlx_bioq		mlx_bioq;			/* outstanding I/O operations */
     int			mlx_waitbufs;			/* number of bufs awaiting commands */
+    int			mlx_stall_ticks;		/* DF-5058: no-progress seconds */
 
     /* controller status */
     int			mlx_geom;