⬢ DragonFlyBSD Kernel Audit
DF-4613 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/dev/raid/ips/ips.c b/sys/dev/raid/ips/ips.c
index 1111111..2222222 100644
--- a/sys/dev/raid/ips/ips.c
+++ b/sys/dev/raid/ips/ips.c
@@ -352,7 +352,22 @@ ips_timeout(void *arg)
 		 * Grr, I hate this solution. I run waiting commands
 		 * one at a time and error them out just before they
 		 * would go to the card. This sucks.
 		 */
-		} else
+		} else
 			sc->state &= ~IPS_TIMEOUT;
 	}
+	/*
+	 * DF-4613: the forced reinit issues config-sync / error-table
+	 * commands and tsleeps for their completion (ips_commands.c:722,743).
+	 * That completion is only delivered by the interrupt handler, which
+	 * must first acquire sc->queue_lock (ips.c:585/769).  Running the
+	 * reinit with queue_lock held therefore deadlocks the softclock
+	 * thread and the IPS ithread permanently (timer-path twin of the
+	 * DF-2163 ioctl deadlock).  Drop the lock around the reinit.
+	 */
+	lockmgr(&sc->queue_lock, LK_RELEASE);
+	if (!state && (sc->state & IPS_TIMEOUT)) {
+		if (sc->ips_adapter_reinit(sc, 1)) {
+			device_printf(sc->dev, "AIEE! adapter reset failed, "
+			    "giving up and going home! Have a nice day.\n");
+			sc->state |= IPS_OFFLINE;
+		}
+		sc->state &= ~IPS_TIMEOUT;
+	}
+	lockmgr(&sc->queue_lock, LK_EXCLUSIVE|LK_RETRY);
 	if (sc->state != IPS_OFFLINE)
 		callout_reset(&sc->timer, 10 * hz, ips_timeout, sc);
-	lockmgr(&sc->queue_lock, LK_RELEASE);
 }
diff --git a/sys/dev/raid/ips/ips_commands.c b/sys/dev/raid/ips/ips_commands.c
index 1111111..2222222 100644
--- a/sys/dev/raid/ips/ips_commands.c
+++ b/sys/dev/raid/ips/ips_commands.c
@@ -719,7 +719,7 @@ ips_send_config_sync_cmd(ips_command_t *command)
 	sc->ips_issue_cmd(command);
 	if (command->status.value != IPS_ERROR_STATUS)
-		ips_timed_wait(command, "ipssyn", 0);
+		ips_timed_wait(command, "ipssyn", 60 * hz);
 	ips_insert_free_cmd(sc, command);
 	return 0;
 }
@@ -740,7 +740,7 @@ ips_send_error_table_cmd(ips_command_t *command)
 	sc->ips_issue_cmd(command);
 	if (command->status.value != IPS_ERROR_STATUS)
-		ips_timed_wait(command, "ipsetc", 0);
+		ips_timed_wait(command, "ipsetc", 60 * hz);
 	ips_insert_free_cmd(sc, command);
 	return 0;
 }