diff options
author | mav <mav@FreeBSD.org> | 2014-07-07 05:48:11 +0000 |
---|---|---|
committer | mav <mav@FreeBSD.org> | 2014-07-07 05:48:11 +0000 |
commit | 17f8e3065c7be0c80b168ee0ce8399837fa18115 (patch) | |
tree | bd4917ced5e1673bf1c78c70420b51c8342525a7 | |
parent | 4be2431f80f539b353e8df5083a7c6ab6ec42cd9 (diff) | |
download | FreeBSD-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.c | 37 | ||||
-rw-r--r-- | sys/cam/ctl/ctl_frontend_iscsi.h | 1 |
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; |