iscsi,iser-target: Initiate termination only once
Since commit 0fc4ea701fcf ("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: Slava Shwartsman <valyushash@gmail.com> Signed-off-by: Sagi Grimberg <sagig@mellanox.com> Cc: <stable@vger.kernel.org> # v3.10+ Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
This commit is contained in:
parent
13ba564c95
commit
954f23722b
@ -777,6 +777,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)
|
||||||
{
|
{
|
||||||
@ -785,33 +812,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;
|
||||||
|
|
||||||
@ -824,18 +833,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);
|
||||||
@ -853,11 +868,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;
|
||||||
@ -2046,7 +2064,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);
|
||||||
@ -3219,10 +3237,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 && !isert_conn->disconnect) {
|
|
||||||
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..
|
||||||
@ -3231,13 +3245,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 {
|
|||||||
#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
|
||||||
|
@ -1204,6 +1204,9 @@ old_sess_out:
|
|||||||
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);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user