IB/iser: Fix device removal flow
authorRoi Dayan <roid@mellanox.com>
Wed, 8 May 2013 12:21:17 +0000 (12:21 +0000)
committerRoland Dreier <roland@purestorage.com>
Wed, 5 Jun 2013 00:03:11 +0000 (17:03 -0700)
Change the code to destroy the "last opened" rdma_cm id after making
sure we released all other objects (QP, CQs, PD, etc) associated with
the IB device.

Since iser accesses the IB device using the rdma_cm id, we need to
free any objects that are related to the device that is associated
with the rdma_cm id prior to destroying that id.  When this isn't
done, the low level driver that created this device can be unloaded
before iser has a chance to free all the objects and a such a call may
invoke code segment which isn't valid any more and crash.

Cc: Sean Hefty <sean.hefty@intel.com
Signed-off-by: Roi Dayan <roid@mellanox.com>
Signed-off-by: Or Gerlitz <ogerlitz@mellanox.com>
Signed-off-by: Roland Dreier <roland@purestorage.com>
drivers/infiniband/ulp/iser/iser_verbs.c

index 5278916c31038cdea28ad9a524d2aa18d653e21d..f13cc227eed7ad7f578e275f47e1d455758bd783 100644 (file)
@@ -292,10 +292,10 @@ out_err:
 }
 
 /**
- * releases the FMR pool, QP and CMA ID objects, returns 0 on success,
+ * releases the FMR pool and QP objects, returns 0 on success,
  * -1 on failure
  */
-static int iser_free_ib_conn_res(struct iser_conn *ib_conn, int can_destroy_id)
+static int iser_free_ib_conn_res(struct iser_conn *ib_conn)
 {
        int cq_index;
        BUG_ON(ib_conn == NULL);
@@ -314,13 +314,9 @@ static int iser_free_ib_conn_res(struct iser_conn *ib_conn, int can_destroy_id)
 
                rdma_destroy_qp(ib_conn->cma_id);
        }
-       /* if cma handler context, the caller acts s.t the cma destroy the id */
-       if (ib_conn->cma_id != NULL && can_destroy_id)
-               rdma_destroy_id(ib_conn->cma_id);
 
        ib_conn->fmr_pool = NULL;
        ib_conn->qp       = NULL;
-       ib_conn->cma_id   = NULL;
        kfree(ib_conn->page_vec);
 
        if (ib_conn->login_buf) {
@@ -415,11 +411,16 @@ static void iser_conn_release(struct iser_conn *ib_conn, int can_destroy_id)
        list_del(&ib_conn->conn_list);
        mutex_unlock(&ig.connlist_mutex);
        iser_free_rx_descriptors(ib_conn);
-       iser_free_ib_conn_res(ib_conn, can_destroy_id);
+       iser_free_ib_conn_res(ib_conn);
        ib_conn->device = NULL;
        /* on EVENT_ADDR_ERROR there's no device yet for this conn */
        if (device != NULL)
                iser_device_try_release(device);
+       /* if cma handler context, the caller actually destroy the id */
+       if (ib_conn->cma_id != NULL && can_destroy_id) {
+               rdma_destroy_id(ib_conn->cma_id);
+               ib_conn->cma_id = NULL;
+       }
        iscsi_destroy_endpoint(ib_conn->ep);
 }