Fixes administrative disconnect flow, discriminating between iscsi and iser. When closing connections administratively, iscsi flow was moving the connection to STATE_CLOSE and setting socket fd polling mask to POLL{IN|OUT|ERR} so that the next time it gets polled, the closing flow starts properly. Although iser has separated from iscsi/tcp as a distinct transport, it still shares with it the session management mechanism; access to targets through tgtadm also passes through the original iscsi code. Closing connections administratively is one of the cases where such common path exists. The problem is that iser can't use the same socket-based signalling mechanism. Thus a new transport api .ep_force_close is introduced, allowing to differentiate between flows during forced disconnection. Signed-off-by: Alexander Nezhinsky <alexandern@xxxxxxxxxxxx> --- usr/iscsi/conn.c | 6 ++---- usr/iscsi/iscsi_tcp.c | 7 +++++++ usr/iscsi/iscsid.h | 2 +- usr/iscsi/iser.c | 11 +++++++++++ usr/iscsi/target.c | 2 +- usr/iscsi/transport.h | 1 + 6 files changed, 23 insertions(+), 6 deletions(-) diff --git a/usr/iscsi/conn.c b/usr/iscsi/conn.c index a3af6a4..53e719e 100644 --- a/usr/iscsi/conn.c +++ b/usr/iscsi/conn.c @@ -216,7 +216,7 @@ int conn_take_fd(struct iscsi_connection *conn) } /* called by tgtadm */ -int conn_close_force(uint32_t tid, uint64_t sid, uint32_t cid) +int conn_close_admin(uint32_t tid, uint64_t sid, uint32_t cid) { struct iscsi_target* target = NULL; struct iscsi_session *session; @@ -233,9 +233,7 @@ int conn_close_force(uint32_t tid, uint64_t sid, uint32_t cid) list_for_each_entry(conn, &session->conn_list, clist) { if (conn->cid == cid) { eprintf("close %" PRIx64 " %u\n", sid, cid); - conn->state = STATE_CLOSE; - conn->tp->ep_event_modify(conn, - EPOLLIN|EPOLLOUT|EPOLLERR); + conn->tp->ep_force_close(conn); return TGTADM_SUCCESS; } } diff --git a/usr/iscsi/iscsi_tcp.c b/usr/iscsi/iscsi_tcp.c index 8fc145f..0fbb671 100644 --- a/usr/iscsi/iscsi_tcp.c +++ b/usr/iscsi/iscsi_tcp.c @@ -384,6 +384,12 @@ static int iscsi_tcp_getpeername(struct iscsi_connection *conn, return getpeername(tcp_conn->fd, sa, len); } +static void iscsi_tcp_conn_force_close(struct iscsi_connection *conn) +{ + conn->state = STATE_CLOSE; + conn->tp->ep_event_modify(conn, EPOLLIN|EPOLLOUT|EPOLLERR); +} + static struct iscsi_transport iscsi_tcp = { .name = "iscsi", .rdma = 0, @@ -397,6 +403,7 @@ static struct iscsi_transport iscsi_tcp = { .ep_write_begin = iscsi_tcp_write_begin, .ep_write_end = iscsi_tcp_write_end, .ep_close = iscsi_tcp_close, + .ep_force_close = iscsi_tcp_conn_force_close, .ep_release = iscsi_tcp_release, .ep_show = iscsi_tcp_show, .ep_event_modify = iscsi_event_modify, diff --git a/usr/iscsi/iscsid.h b/usr/iscsi/iscsid.h index be585bb..e496712 100644 --- a/usr/iscsi/iscsid.h +++ b/usr/iscsi/iscsid.h @@ -292,7 +292,7 @@ extern int conn_get(struct iscsi_connection *conn); extern struct iscsi_connection * conn_find(struct iscsi_session *session, uint32_t cid); extern int conn_take_fd(struct iscsi_connection *conn); extern void conn_add_to_session(struct iscsi_connection *conn, struct iscsi_session *session); -extern int conn_close_force(uint32_t tid, uint64_t sid, uint32_t cid); +extern int conn_close_admin(uint32_t tid, uint64_t sid, uint32_t cid); /* iscsid.c */ extern char *text_key_find(struct iscsi_connection *conn, char *searchKey); diff --git a/usr/iscsi/iser.c b/usr/iscsi/iser.c index 926832b..5d56e07 100644 --- a/usr/iscsi/iser.c +++ b/usr/iscsi/iser.c @@ -1215,6 +1215,16 @@ void iser_conn_close(struct iser_conn *conn) &conn->h, conn->cm_id, conn->h.refcount); } +static void iser_conn_force_close(struct iscsi_connection *iscsi_conn) +{ + struct iser_conn *conn = ISER_CONN(iscsi_conn); + + eprintf("conn:%p\n", &conn->h); + conn->h.closed = 1; + iser_conn_close(conn); + iser_conn_put(conn); +} + /* * Called when the connection is freed, from iscsi, but won't do anything until * all posted WRs have gone away. So also called again from RX progress when @@ -3415,6 +3425,7 @@ static struct iscsi_transport iscsi_iser = { .rdma = 1, .data_padding = 1, .ep_show = iser_show, + .ep_force_close = iser_conn_force_close, .ep_getsockname = iser_getsockname, .ep_getpeername = iser_getpeername, }; diff --git a/usr/iscsi/target.c b/usr/iscsi/target.c index 61166e1..fd3ed92 100644 --- a/usr/iscsi/target.c +++ b/usr/iscsi/target.c @@ -513,7 +513,7 @@ int iscsi_target_update(int mode, int op, int tid, uint64_t sid, uint64_t lun, break; case MODE_CONNECTION: if (op == OP_DELETE) - err = conn_close_force(tid, sid, cid); + err = conn_close_admin(tid, sid, cid); break; default: break; diff --git a/usr/iscsi/transport.h b/usr/iscsi/transport.h index 92a6f0a..af4af21 100644 --- a/usr/iscsi/transport.h +++ b/usr/iscsi/transport.h @@ -28,6 +28,7 @@ struct iscsi_transport { int (*ep_rdma_read)(struct iscsi_connection *conn); int (*ep_rdma_write)(struct iscsi_connection *conn); size_t (*ep_close)(struct iscsi_connection *conn); + void (*ep_force_close)(struct iscsi_connection *conn); void (*ep_release)(struct iscsi_connection *conn); int (*ep_show)(struct iscsi_connection *conn, char *buf, int rest); -- 1.7.1 -- To unsubscribe from this list: send the line "unsubscribe stgt" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html