Commit 96b50563 authored by Sagi Grimberg's avatar Sagi Grimberg Committed by Luis Henriques

iscsi,iser-target: Initiate termination only once

commit 954f2372 upstream.

Since commit 0fc4ea70 ("Target/iser: Don't put isert_conn inside
disconnected handler") we put the conn kref in isert_wait_conn, so we
need .wait_conn to be invoked also in the error path.

Introduce call to isert_conn_terminate (called under lock)
which transitions the connection state to TERMINATING and calls
rdma_disconnect. If the state is already teminating, just bail
out back (temination started).

Also, make sure to destroy the connection when getting a connect
error event if didn't get to connected (state UP). Same for the
handling of REJECTED and UNREACHABLE cma events.

Squashed:

iscsi-target: Add call to wait_conn in establishment error flow
Reported-by: default avatarSlava Shwartsman <valyushash@gmail.com>
Signed-off-by: default avatarSagi Grimberg <sagig@mellanox.com>
Signed-off-by: default avatarNicholas Bellinger <nab@linux-iscsi.org>
[ luis: backported to 3.16: adjusted context ]
Signed-off-by: default avatarLuis Henriques <luis.henriques@canonical.com>
parent 1eadc8e9
...@@ -775,6 +775,33 @@ isert_put_conn(struct isert_conn *isert_conn) ...@@ -775,6 +775,33 @@ isert_put_conn(struct isert_conn *isert_conn)
kref_put(&isert_conn->conn_kref, isert_release_conn_kref); kref_put(&isert_conn->conn_kref, isert_release_conn_kref);
} }
/**
* isert_conn_terminate() - Initiate connection termination
* @isert_conn: isert connection struct
*
* Notes:
* In case the connection state is UP, move state
* to TEMINATING and start teardown sequence (rdma_disconnect).
*
* This routine must be called with conn_mutex held. Thus it is
* safe to call multiple times.
*/
static void
isert_conn_terminate(struct isert_conn *isert_conn)
{
int err;
if (isert_conn->state == ISER_CONN_UP) {
isert_conn->state = ISER_CONN_TERMINATING;
pr_info("Terminating conn %p state %d\n",
isert_conn, isert_conn->state);
err = rdma_disconnect(isert_conn->conn_cm_id);
if (err)
pr_warn("Failed rdma_disconnect isert_conn %p\n",
isert_conn);
}
}
static void static void
isert_disconnect_work(struct work_struct *work) isert_disconnect_work(struct work_struct *work)
{ {
...@@ -783,33 +810,15 @@ isert_disconnect_work(struct work_struct *work) ...@@ -783,33 +810,15 @@ isert_disconnect_work(struct work_struct *work)
pr_debug("isert_disconnect_work(): >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); pr_debug("isert_disconnect_work(): >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
mutex_lock(&isert_conn->conn_mutex); mutex_lock(&isert_conn->conn_mutex);
if (isert_conn->state == ISER_CONN_UP) isert_conn_terminate(isert_conn);
isert_conn->state = ISER_CONN_TERMINATING;
if (isert_conn->post_recv_buf_count == 0 &&
atomic_read(&isert_conn->post_send_buf_count) == 0) {
mutex_unlock(&isert_conn->conn_mutex);
goto wake_up;
}
if (!isert_conn->conn_cm_id) {
mutex_unlock(&isert_conn->conn_mutex);
isert_put_conn(isert_conn);
return;
}
if (isert_conn->disconnect) {
/* Send DREQ/DREP towards our initiator */
rdma_disconnect(isert_conn->conn_cm_id);
}
mutex_unlock(&isert_conn->conn_mutex); mutex_unlock(&isert_conn->conn_mutex);
wake_up: pr_info("conn %p completing conn_wait\n", isert_conn);
complete(&isert_conn->conn_wait); complete(&isert_conn->conn_wait);
} }
static int static int
isert_disconnected_handler(struct rdma_cm_id *cma_id, bool disconnect) isert_disconnected_handler(struct rdma_cm_id *cma_id)
{ {
struct isert_conn *isert_conn; struct isert_conn *isert_conn;
...@@ -822,18 +831,24 @@ isert_disconnected_handler(struct rdma_cm_id *cma_id, bool disconnect) ...@@ -822,18 +831,24 @@ isert_disconnected_handler(struct rdma_cm_id *cma_id, bool disconnect)
isert_conn = (struct isert_conn *)cma_id->context; isert_conn = (struct isert_conn *)cma_id->context;
isert_conn->disconnect = disconnect;
INIT_WORK(&isert_conn->conn_logout_work, isert_disconnect_work); INIT_WORK(&isert_conn->conn_logout_work, isert_disconnect_work);
schedule_work(&isert_conn->conn_logout_work); schedule_work(&isert_conn->conn_logout_work);
return 0; return 0;
} }
static void
isert_connect_error(struct rdma_cm_id *cma_id)
{
struct isert_conn *isert_conn = (struct isert_conn *)cma_id->context;
isert_put_conn(isert_conn);
}
static int static int
isert_cma_handler(struct rdma_cm_id *cma_id, struct rdma_cm_event *event) isert_cma_handler(struct rdma_cm_id *cma_id, struct rdma_cm_event *event)
{ {
int ret = 0; int ret = 0;
bool disconnect = false;
pr_debug("isert_cma_handler: event %d status %d conn %p id %p\n", pr_debug("isert_cma_handler: event %d status %d conn %p id %p\n",
event->event, event->status, cma_id->context, cma_id); event->event, event->status, cma_id->context, cma_id);
...@@ -851,11 +866,14 @@ isert_cma_handler(struct rdma_cm_id *cma_id, struct rdma_cm_event *event) ...@@ -851,11 +866,14 @@ isert_cma_handler(struct rdma_cm_id *cma_id, struct rdma_cm_event *event)
case RDMA_CM_EVENT_ADDR_CHANGE: /* FALLTHRU */ case RDMA_CM_EVENT_ADDR_CHANGE: /* FALLTHRU */
case RDMA_CM_EVENT_DISCONNECTED: /* FALLTHRU */ case RDMA_CM_EVENT_DISCONNECTED: /* FALLTHRU */
case RDMA_CM_EVENT_DEVICE_REMOVAL: /* FALLTHRU */ case RDMA_CM_EVENT_DEVICE_REMOVAL: /* FALLTHRU */
disconnect = true;
case RDMA_CM_EVENT_TIMEWAIT_EXIT: /* FALLTHRU */ case RDMA_CM_EVENT_TIMEWAIT_EXIT: /* FALLTHRU */
ret = isert_disconnected_handler(cma_id, disconnect); ret = isert_disconnected_handler(cma_id);
break; break;
case RDMA_CM_EVENT_REJECTED: /* FALLTHRU */
case RDMA_CM_EVENT_UNREACHABLE: /* FALLTHRU */
case RDMA_CM_EVENT_CONNECT_ERROR: case RDMA_CM_EVENT_CONNECT_ERROR:
isert_connect_error(cma_id);
break;
default: default:
pr_err("Unhandled RDMA CMA event: %d\n", event->event); pr_err("Unhandled RDMA CMA event: %d\n", event->event);
break; break;
...@@ -2044,7 +2062,7 @@ isert_cq_rx_comp_err(struct isert_conn *isert_conn) ...@@ -2044,7 +2062,7 @@ isert_cq_rx_comp_err(struct isert_conn *isert_conn)
msleep(3000); msleep(3000);
mutex_lock(&isert_conn->conn_mutex); mutex_lock(&isert_conn->conn_mutex);
isert_conn->state = ISER_CONN_DOWN; isert_conn_terminate(isert_conn);
mutex_unlock(&isert_conn->conn_mutex); mutex_unlock(&isert_conn->conn_mutex);
iscsit_cause_connection_reinstatement(isert_conn->conn, 0); iscsit_cause_connection_reinstatement(isert_conn->conn, 0);
...@@ -3231,10 +3249,6 @@ static void isert_wait_conn(struct iscsi_conn *conn) ...@@ -3231,10 +3249,6 @@ static void isert_wait_conn(struct iscsi_conn *conn)
pr_debug("isert_wait_conn: Starting \n"); pr_debug("isert_wait_conn: Starting \n");
mutex_lock(&isert_conn->conn_mutex); mutex_lock(&isert_conn->conn_mutex);
if (isert_conn->conn_cm_id) {
pr_debug("Calling rdma_disconnect from isert_wait_conn\n");
rdma_disconnect(isert_conn->conn_cm_id);
}
/* /*
* Only wait for conn_wait_comp_err if the isert_conn made it * Only wait for conn_wait_comp_err if the isert_conn made it
* into full feature phase.. * into full feature phase..
...@@ -3243,13 +3257,17 @@ static void isert_wait_conn(struct iscsi_conn *conn) ...@@ -3243,13 +3257,17 @@ static void isert_wait_conn(struct iscsi_conn *conn)
mutex_unlock(&isert_conn->conn_mutex); mutex_unlock(&isert_conn->conn_mutex);
return; return;
} }
if (isert_conn->state == ISER_CONN_UP) isert_conn_terminate(isert_conn);
isert_conn->state = ISER_CONN_TERMINATING;
mutex_unlock(&isert_conn->conn_mutex); mutex_unlock(&isert_conn->conn_mutex);
wait_for_completion(&isert_conn->conn_wait_comp_err); wait_for_completion(&isert_conn->conn_wait_comp_err);
wait_for_completion(&isert_conn->conn_wait); wait_for_completion(&isert_conn->conn_wait);
mutex_lock(&isert_conn->conn_mutex);
isert_conn->state = ISER_CONN_DOWN;
mutex_unlock(&isert_conn->conn_mutex);
pr_info("Destroying conn %p\n", isert_conn);
isert_put_conn(isert_conn); isert_put_conn(isert_conn);
} }
......
...@@ -150,7 +150,6 @@ struct isert_conn { ...@@ -150,7 +150,6 @@ struct isert_conn {
#define ISERT_COMP_BATCH_COUNT 8 #define ISERT_COMP_BATCH_COUNT 8
int conn_comp_batch; int conn_comp_batch;
struct llist_head conn_comp_llist; struct llist_head conn_comp_llist;
bool disconnect;
}; };
#define ISERT_MAX_CQ 64 #define ISERT_MAX_CQ 64
......
...@@ -1206,6 +1206,9 @@ void iscsi_target_login_sess_out(struct iscsi_conn *conn, ...@@ -1206,6 +1206,9 @@ void iscsi_target_login_sess_out(struct iscsi_conn *conn,
conn->sock = NULL; conn->sock = NULL;
} }
if (conn->conn_transport->iscsit_wait_conn)
conn->conn_transport->iscsit_wait_conn(conn);
if (conn->conn_transport->iscsit_free_conn) if (conn->conn_transport->iscsit_free_conn)
conn->conn_transport->iscsit_free_conn(conn); conn->conn_transport->iscsit_free_conn(conn);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment