svn commit: r293659 - head/sys/dev/iscsi

Steven Hartland smh at FreeBSD.org
Mon Jan 11 10:24:31 UTC 2016


Author: smh
Date: Mon Jan 11 10:24:30 2016
New Revision: 293659
URL: https://svnweb.freebsd.org/changeset/base/293659

Log:
  Close iSCSI sessions on shutdown
  
  Ensure that all iSCSI sessions are correctly terminated during shutdown.
  
  * Enhances the changes done by r286226 (D3052).
  * Add shutdown post sync event to run after filesystem shutdown
    (SHUTDOWN_PRI_FIRST) but before CAM shutdown (SHUTDOWN_PRI_DEFAULT).
  * Changes iscsi_maintenance_thread to processes terminate in preference to
    reconnect.
  
  Reviewed by:	trasz
  MFC after:	2 weeks
  Sponsored by:	Multiplay
  Differential Revision:	https://reviews.freebsd.org/D4429

Modified:
  head/sys/dev/iscsi/iscsi.c
  head/sys/dev/iscsi/iscsi.h

Modified: head/sys/dev/iscsi/iscsi.c
==============================================================================
--- head/sys/dev/iscsi/iscsi.c	Mon Jan 11 09:15:25 2016	(r293658)
+++ head/sys/dev/iscsi/iscsi.c	Mon Jan 11 10:24:30 2016	(r293659)
@@ -98,6 +98,9 @@ SYSCTL_INT(_kern_iscsi, OID_AUTO, maxtag
 static int fail_on_disconnection = 0;
 SYSCTL_INT(_kern_iscsi, OID_AUTO, fail_on_disconnection, CTLFLAG_RWTUN,
     &fail_on_disconnection, 0, "Destroy CAM SIM on connection failure");
+static int fail_on_shutdown = 1;
+SYSCTL_INT(_kern_iscsi, OID_AUTO, fail_on_shutdown, CTLFLAG_RWTUN,
+    &fail_on_shutdown, 0, "Fail disconnected sessions on shutdown");
 
 static MALLOC_DEFINE(M_ISCSI, "iSCSI", "iSCSI initiator");
 static uma_zone_t iscsi_outstanding_zone;
@@ -417,8 +420,6 @@ iscsi_maintenance_thread_terminate(struc
 
 	sc = is->is_softc;
 	sx_xlock(&sc->sc_lock);
-	TAILQ_REMOVE(&sc->sc_sessions, is, is_next);
-	sx_xunlock(&sc->sc_lock);
 
 	icl_conn_close(is->is_conn);
 	callout_drain(&is->is_callout);
@@ -450,6 +451,9 @@ iscsi_maintenance_thread_terminate(struc
 #ifdef ICL_KERNEL_PROXY
 	cv_destroy(&is->is_login_cv);
 #endif
+	TAILQ_REMOVE(&sc->sc_sessions, is, is_next);
+	sx_xunlock(&sc->sc_lock);
+
 	ISCSI_SESSION_DEBUG(is, "terminated");
 	free(is, M_ISCSI);
 
@@ -473,12 +477,7 @@ iscsi_maintenance_thread(void *arg)
 		    STAILQ_EMPTY(&is->is_postponed))
 			cv_wait(&is->is_maintenance_cv, &is->is_lock);
 
-		if (is->is_reconnecting) {
-			ISCSI_SESSION_UNLOCK(is);
-			iscsi_maintenance_thread_reconnect(is);
-			continue;
-		}
-
+		/* Terminate supersedes reconnect. */
 		if (is->is_terminating) {
 			ISCSI_SESSION_UNLOCK(is);
 			iscsi_maintenance_thread_terminate(is);
@@ -486,6 +485,12 @@ iscsi_maintenance_thread(void *arg)
 			return;
 		}
 
+		if (is->is_reconnecting) {
+			ISCSI_SESSION_UNLOCK(is);
+			iscsi_maintenance_thread_reconnect(is);
+			continue;
+		}
+
 		iscsi_session_send_postponed(is);
 		ISCSI_SESSION_UNLOCK(is);
 	}
@@ -605,6 +610,11 @@ iscsi_callout(void *context)
 	return;
 
 out:
+	if (is->is_terminating) {
+		ISCSI_SESSION_UNLOCK(is);
+		return;
+	}
+
 	ISCSI_SESSION_UNLOCK(is);
 
 	if (reconnect_needed)
@@ -2326,30 +2336,62 @@ iscsi_poll(struct cam_sim *sim)
 }
 
 static void
-iscsi_shutdown(struct iscsi_softc *sc)
+iscsi_terminate_sessions(struct iscsi_softc *sc)
 {
 	struct iscsi_session *is;
 
-	/*
-	 * Trying to reconnect during system shutdown would lead to hang.
-	 */
-	fail_on_disconnection = 1;
+	sx_slock(&sc->sc_lock);
+	TAILQ_FOREACH(is, &sc->sc_sessions, is_next)
+		iscsi_session_terminate(is);
+	while(!TAILQ_EMPTY(&sc->sc_sessions)) {
+		ISCSI_DEBUG("waiting for sessions to terminate");
+		cv_wait(&sc->sc_cv, &sc->sc_lock);
+	}
+	ISCSI_DEBUG("all sessions terminated");
+	sx_sunlock(&sc->sc_lock);
+}
+
+static void
+iscsi_shutdown_pre(struct iscsi_softc *sc)
+{
+	struct iscsi_session *is;
+
+	if (!fail_on_shutdown)
+		return;
 
 	/*
 	 * If we have any sessions waiting for reconnection, request
 	 * maintenance thread to fail them immediately instead of waiting
 	 * for reconnect timeout.
+	 *
+	 * This prevents LUNs with mounted filesystems that are supported
+	 * by disconnected iSCSI sessions from hanging, however it will
+	 * fail all queued BIOs.
 	 */
+	ISCSI_DEBUG("forcing failing all disconnected sessions due to shutdown");
+
+	fail_on_disconnection = 1;
+
 	sx_slock(&sc->sc_lock);
 	TAILQ_FOREACH(is, &sc->sc_sessions, is_next) {
 		ISCSI_SESSION_LOCK(is);
-		if (is->is_waiting_for_iscsid)
+		if (!is->is_connected) {
+			ISCSI_SESSION_DEBUG(is, "force failing disconnected session early");
 			iscsi_session_reconnect(is);
+		}
 		ISCSI_SESSION_UNLOCK(is);
 	}
 	sx_sunlock(&sc->sc_lock);
 }
 
+static void
+iscsi_shutdown_post(struct iscsi_softc *sc)
+{
+
+	ISCSI_DEBUG("removing all sessions due to shutdown");
+	iscsi_terminate_sessions(sc);
+}
+
 static int
 iscsi_load(void)
 {
@@ -2372,8 +2414,16 @@ iscsi_load(void)
 	}
 	sc->sc_cdev->si_drv1 = sc;
 
-	sc->sc_shutdown_eh = EVENTHANDLER_REGISTER(shutdown_pre_sync,
-	    iscsi_shutdown, sc, SHUTDOWN_PRI_DEFAULT-1);
+	sc->sc_shutdown_pre_eh = EVENTHANDLER_REGISTER(shutdown_pre_sync,
+	    iscsi_shutdown_pre, sc, SHUTDOWN_PRI_FIRST);
+	/*
+	 * shutdown_post_sync needs to run after filesystem shutdown and before
+	 * CAM shutdown - otherwise when rebooting with an iSCSI session that is
+	 * disconnected but has outstanding requests, dashutdown() will hang on
+	 * cam_periph_runccb().
+	 */
+	sc->sc_shutdown_post_eh = EVENTHANDLER_REGISTER(shutdown_post_sync,
+	    iscsi_shutdown_post, sc, SHUTDOWN_PRI_DEFAULT - 1);
 
 	return (0);
 }
@@ -2381,7 +2431,6 @@ iscsi_load(void)
 static int
 iscsi_unload(void)
 {
-	struct iscsi_session *is, *tmp;
 
 	if (sc->sc_cdev != NULL) {
 		ISCSI_DEBUG("removing device node");
@@ -2389,18 +2438,12 @@ iscsi_unload(void)
 		ISCSI_DEBUG("device node removed");
 	}
 
-	if (sc->sc_shutdown_eh != NULL)
-		EVENTHANDLER_DEREGISTER(shutdown_pre_sync, sc->sc_shutdown_eh);
+	if (sc->sc_shutdown_pre_eh != NULL)
+		EVENTHANDLER_DEREGISTER(shutdown_pre_sync, sc->sc_shutdown_pre_eh);
+	if (sc->sc_shutdown_post_eh != NULL)
+		EVENTHANDLER_DEREGISTER(shutdown_post_sync, sc->sc_shutdown_post_eh);
 
-	sx_slock(&sc->sc_lock);
-	TAILQ_FOREACH_SAFE(is, &sc->sc_sessions, is_next, tmp)
-		iscsi_session_terminate(is);
-	while(!TAILQ_EMPTY(&sc->sc_sessions)) {
-		ISCSI_DEBUG("waiting for sessions to terminate");
-		cv_wait(&sc->sc_cv, &sc->sc_lock);
-	}
-	ISCSI_DEBUG("all sessions terminated");
-	sx_sunlock(&sc->sc_lock);
+	iscsi_terminate_sessions(sc);
 
 	uma_zdestroy(iscsi_outstanding_zone);
 	sx_destroy(&sc->sc_lock);

Modified: head/sys/dev/iscsi/iscsi.h
==============================================================================
--- head/sys/dev/iscsi/iscsi.h	Mon Jan 11 09:15:25 2016	(r293658)
+++ head/sys/dev/iscsi/iscsi.h	Mon Jan 11 10:24:30 2016	(r293659)
@@ -131,7 +131,8 @@ struct iscsi_softc {
 	TAILQ_HEAD(, iscsi_session)	sc_sessions;
 	struct cv			sc_cv;
 	unsigned int			sc_last_session_id;
-	eventhandler_tag		sc_shutdown_eh;
+	eventhandler_tag		sc_shutdown_pre_eh;
+	eventhandler_tag		sc_shutdown_post_eh;
 };
 
 #endif /* !ISCSI_H */


More information about the svn-src-head mailing list