Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 954f2372 authored by Sagi Grimberg's avatar Sagi Grimberg Committed by Nicholas Bellinger
Browse files

iscsi,iser-target: Initiate termination only once



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>
Cc: <stable@vger.kernel.org> # v3.10+
Signed-off-by: default avatarNicholas Bellinger <nab@linux-iscsi.org>
parent 13ba564c
Loading
Loading
Loading
Loading
+51 −33
Original line number Diff line number Diff line
@@ -777,41 +777,50 @@ isert_put_conn(struct isert_conn *isert_conn)
	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_disconnect_work(struct work_struct *work)
isert_conn_terminate(struct isert_conn *isert_conn)
{
	struct isert_conn *isert_conn = container_of(work,
				struct isert_conn, conn_logout_work);
	int err;

	pr_debug("isert_disconnect_work(): >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
	mutex_lock(&isert_conn->conn_mutex);
	if (isert_conn->state == ISER_CONN_UP)
	if (isert_conn->state == ISER_CONN_UP) {
		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;
		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);
	}
	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);
	}
static void
isert_disconnect_work(struct work_struct *work)
{
	struct isert_conn *isert_conn = container_of(work,
				struct isert_conn, conn_logout_work);

	pr_debug("isert_disconnect_work(): >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
	mutex_lock(&isert_conn->conn_mutex);
	isert_conn_terminate(isert_conn);
	mutex_unlock(&isert_conn->conn_mutex);

wake_up:
	pr_info("conn %p completing conn_wait\n", isert_conn);
	complete(&isert_conn->conn_wait);
}

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;

@@ -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->disconnect = disconnect;
	INIT_WORK(&isert_conn->conn_logout_work, isert_disconnect_work);
	schedule_work(&isert_conn->conn_logout_work);

	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
isert_cma_handler(struct rdma_cm_id *cma_id, struct rdma_cm_event *event)
{
	int ret = 0;
	bool disconnect = false;

	pr_debug("isert_cma_handler: event %d status %d conn %p id %p\n",
		 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_DISCONNECTED:   /* FALLTHRU */
	case RDMA_CM_EVENT_DEVICE_REMOVAL: /* FALLTHRU */
		disconnect = true;
	case RDMA_CM_EVENT_TIMEWAIT_EXIT:  /* FALLTHRU */
		ret = isert_disconnected_handler(cma_id, disconnect);
		ret = isert_disconnected_handler(cma_id);
		break;
	case RDMA_CM_EVENT_REJECTED:       /* FALLTHRU */
	case RDMA_CM_EVENT_UNREACHABLE:    /* FALLTHRU */
	case RDMA_CM_EVENT_CONNECT_ERROR:
		isert_connect_error(cma_id);
		break;
	default:
		pr_err("Unhandled RDMA CMA event: %d\n", event->event);
		break;
@@ -2046,7 +2064,7 @@ isert_cq_rx_comp_err(struct isert_conn *isert_conn)
		msleep(3000);

	mutex_lock(&isert_conn->conn_mutex);
	isert_conn->state = ISER_CONN_DOWN;
	isert_conn_terminate(isert_conn);
	mutex_unlock(&isert_conn->conn_mutex);

	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");

	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
	 * into full feature phase..
@@ -3231,13 +3245,17 @@ static void isert_wait_conn(struct iscsi_conn *conn)
		mutex_unlock(&isert_conn->conn_mutex);
		return;
	}
	if (isert_conn->state == ISER_CONN_UP)
		isert_conn->state = ISER_CONN_TERMINATING;
	isert_conn_terminate(isert_conn);
	mutex_unlock(&isert_conn->conn_mutex);

	wait_for_completion(&isert_conn->conn_wait_comp_err);

	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);
}

+0 −1
Original line number Diff line number Diff line
@@ -150,7 +150,6 @@ struct isert_conn {
#define ISERT_COMP_BATCH_COUNT	8
	int			conn_comp_batch;
	struct llist_head	conn_comp_llist;
	bool                    disconnect;
};

#define ISERT_MAX_CQ 64
+3 −0
Original line number Diff line number Diff line
@@ -1204,6 +1204,9 @@ void iscsi_target_login_sess_out(struct iscsi_conn *conn,
		conn->sock = NULL;
	}

	if (conn->conn_transport->iscsit_wait_conn)
		conn->conn_transport->iscsit_wait_conn(conn);

	if (conn->conn_transport->iscsit_free_conn)
		conn->conn_transport->iscsit_free_conn(conn);