summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormav <mav@FreeBSD.org>2014-07-07 05:48:11 +0000
committermav <mav@FreeBSD.org>2014-07-07 05:48:11 +0000
commit17f8e3065c7be0c80b168ee0ce8399837fa18115 (patch)
treebd4917ced5e1673bf1c78c70420b51c8342525a7
parent4be2431f80f539b353e8df5083a7c6ab6ec42cd9 (diff)
downloadFreeBSD-src-17f8e3065c7be0c80b168ee0ce8399837fa18115.zip
FreeBSD-src-17f8e3065c7be0c80b168ee0ce8399837fa18115.tar.gz
When new connection comes in, check whether we already have session from
the same intiator (Name+ISID). If so -- terminate the old session and let the new one take its place, as required by iSCSI RFC.
-rw-r--r--sys/cam/ctl/ctl_frontend_iscsi.c37
-rw-r--r--sys/cam/ctl/ctl_frontend_iscsi.h1
2 files changed, 30 insertions, 8 deletions
diff --git a/sys/cam/ctl/ctl_frontend_iscsi.c b/sys/cam/ctl/ctl_frontend_iscsi.c
index 6386403..c7c9c27 100644
--- a/sys/cam/ctl/ctl_frontend_iscsi.c
+++ b/sys/cam/ctl/ctl_frontend_iscsi.c
@@ -1087,7 +1087,8 @@ cfiscsi_session_terminate_tasks(struct cfiscsi_session *cs)
break;
CFISCSI_SESSION_WARN(cs, "waiting for CTL to terminate tasks, "
"%d remaining", cs->cs_outstanding_ctl_pdus);
- pause("cfiscsi_terminate", hz / 100);
+ tsleep(__DEVOLATILE(void *, &cs->cs_outstanding_ctl_pdus),
+ 0, "cfiscsi_terminate", hz / 100);
}
}
@@ -1404,7 +1405,7 @@ static void
cfiscsi_ioctl_handoff(struct ctl_iscsi *ci)
{
struct cfiscsi_softc *softc;
- struct cfiscsi_session *cs;
+ struct cfiscsi_session *cs, *cs2;
struct cfiscsi_target *ct;
struct ctl_iscsi_handoff_params *cihp;
int error;
@@ -1500,12 +1501,34 @@ cfiscsi_ioctl_handoff(struct ctl_iscsi *ci)
cihp->initiator_isid[2], cihp->initiator_isid[3],
cihp->initiator_isid[4], cihp->initiator_isid[5]);
+ refcount_acquire(&cs->cs_outstanding_ctl_pdus);
+restart:
+ if (!cs->cs_terminating) {
+ mtx_lock(&softc->lock);
+ TAILQ_FOREACH(cs2, &softc->sessions, cs_next) {
+ if (cs2 != cs && cs2->cs_tasks_aborted == false &&
+ strcmp(cs->cs_initiator_id, cs2->cs_initiator_id) == 0) {
+ cfiscsi_session_terminate(cs2);
+ mtx_unlock(&softc->lock);
+ pause("cfiscsi_reinstate", 1);
+ goto restart;
+ }
+ }
+ mtx_unlock(&softc->lock);
+ }
+
+ /*
+ * Register initiator with CTL.
+ */
+ cfiscsi_session_register_initiator(cs);
+
#ifdef ICL_KERNEL_PROXY
if (cihp->socket > 0) {
#endif
error = icl_conn_handoff(cs->cs_conn, cihp->socket);
if (error != 0) {
- cfiscsi_session_delete(cs);
+ cfiscsi_session_terminate(cs);
+ refcount_release(&cs->cs_outstanding_ctl_pdus);
ci->status = CTL_ISCSI_ERROR;
snprintf(ci->error_str, sizeof(ci->error_str),
"%s: icl_conn_handoff failed with error %d",
@@ -1516,11 +1539,6 @@ cfiscsi_ioctl_handoff(struct ctl_iscsi *ci)
}
#endif
- /*
- * Register initiator with CTL.
- */
- cfiscsi_session_register_initiator(cs);
-
#ifdef ICL_KERNEL_PROXY
cs->cs_login_phase = false;
@@ -1535,6 +1553,7 @@ cfiscsi_ioctl_handoff(struct ctl_iscsi *ci)
}
#endif
+ refcount_release(&cs->cs_outstanding_ctl_pdus);
ci->status = CTL_ISCSI_OK;
}
@@ -2833,7 +2852,9 @@ cfiscsi_done(union ctl_io *io)
* Implicit task termination has just completed; nothing to do.
*/
cs = io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr;
+ cs->cs_tasks_aborted = true;
refcount_release(&cs->cs_outstanding_ctl_pdus);
+ wakeup(__DEVOLATILE(void *, &cs->cs_outstanding_ctl_pdus));
ctl_free_io(io);
return;
}
diff --git a/sys/cam/ctl/ctl_frontend_iscsi.h b/sys/cam/ctl/ctl_frontend_iscsi.h
index 2ef2c9a..76d8254 100644
--- a/sys/cam/ctl/ctl_frontend_iscsi.h
+++ b/sys/cam/ctl/ctl_frontend_iscsi.h
@@ -80,6 +80,7 @@ struct cfiscsi_session {
int cs_portal_group_tag;
struct cv cs_maintenance_cv;
bool cs_terminating;
+ bool cs_tasks_aborted;
size_t cs_max_data_segment_length;
size_t cs_max_burst_length;
bool cs_immediate_data;
OpenPOWER on IntegriCloud