iscsi,iser-target: Initiate termination only once
authorSagi Grimberg <sagig@mellanox.com>
Fri, 30 Jan 2015 22:17:25 +0000 (22:17 +0000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 6 Feb 2015 06:35:41 +0000 (22:35 -0800)
commit 954f23722b5753305be490330cf2680b7a25f4a3 upstream.

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>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/infiniband/ulp/isert/ib_isert.c
drivers/infiniband/ulp/isert/ib_isert.h
drivers/target/iscsi/iscsi_target_login.c

index 0812e98262face472a551d87b2b10e6474e1d375..dd3ede86bb2e3d5b67dcb57269c5647717834717 100644 (file)
@@ -565,6 +565,33 @@ 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_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
 isert_disconnect_work(struct work_struct *work)
 {
@@ -573,33 +600,15 @@ isert_disconnect_work(struct work_struct *work)
 
        pr_debug("isert_disconnect_work(): >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
        mutex_lock(&isert_conn->conn_mutex);
-       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;
-       }
-       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);
-       }
-
+       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;
 
@@ -612,18 +621,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);
@@ -641,11 +656,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;
@@ -1496,7 +1514,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);
@@ -2268,10 +2286,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) {
-               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..
@@ -2280,13 +2294,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);
 }
 
index 032f65abee3694ec56122dd0bd9091eb5e84caa6..df193dc19f614d9cd8b4af7b5cd9ed7e75c1fe85 100644 (file)
@@ -105,7 +105,6 @@ struct isert_conn {
        struct completion       conn_wait;
        struct completion       conn_wait_comp_err;
        struct kref             conn_kref;
-       bool                    disconnect;
 };
 
 #define ISERT_MAX_CQ 64
index e14e105acff8f8bd1d7b5498621ab644a817b2b9..0493e8b1ba8fdd813ef28f23523b26dd3af2f6b2 100644 (file)
@@ -1360,6 +1360,9 @@ old_sess_out:
                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);