aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/iscsi
diff options
context:
space:
mode:
authorSteven Hartland <smh@FreeBSD.org>2016-01-11 10:24:30 +0000
committerSteven Hartland <smh@FreeBSD.org>2016-01-11 10:24:30 +0000
commit481b36c66aa200e9f802d948b5c4ca63abc45266 (patch)
treedf997a579ff7b6f8f64c3f18c00db53e72396236 /sys/dev/iscsi
parentb53f4a640f0ec002d4302d9f0aacb871a6302d1d (diff)
downloadsrc-481b36c66aa200e9f802d948b5c4ca63abc45266.tar.gz
src-481b36c66aa200e9f802d948b5c4ca63abc45266.zip
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
Notes
Notes: svn path=/head/; revision=293659
Diffstat (limited to 'sys/dev/iscsi')
-rw-r--r--sys/dev/iscsi/iscsi.c99
-rw-r--r--sys/dev/iscsi/iscsi.h3
2 files changed, 73 insertions, 29 deletions
diff --git a/sys/dev/iscsi/iscsi.c b/sys/dev/iscsi/iscsi.c
index d792746091da..a9bdaf79dd8f 100644
--- a/sys/dev/iscsi/iscsi.c
+++ b/sys/dev/iscsi/iscsi.c
@@ -98,6 +98,9 @@ SYSCTL_INT(_kern_iscsi, OID_AUTO, maxtags, CTLFLAG_RWTUN, &maxtags,
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(struct iscsi_session *is)
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(struct iscsi_session *is)
#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);
diff --git a/sys/dev/iscsi/iscsi.h b/sys/dev/iscsi/iscsi.h
index fd52fa87a954..a2475f4ac8fb 100644
--- a/sys/dev/iscsi/iscsi.h
+++ b/sys/dev/iscsi/iscsi.h
@@ -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 */