summaryrefslogtreecommitdiffstats
path: root/drivers/infiniband/ulp/iser/iscsi_iser.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/infiniband/ulp/iser/iscsi_iser.c')
-rw-r--r--drivers/infiniband/ulp/iser/iscsi_iser.c42
1 files changed, 39 insertions, 3 deletions
diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c
index 9b34946eb00..8a1bfb7277c 100644
--- a/drivers/infiniband/ulp/iser/iscsi_iser.c
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.c
@@ -305,10 +305,18 @@ iscsi_iser_conn_destroy(struct iscsi_cls_conn *cls_conn)
{
struct iscsi_conn *conn = cls_conn->dd_data;
struct iscsi_iser_conn *iser_conn = conn->dd_data;
+ struct iser_conn *ib_conn = iser_conn->ib_conn;
- if (iser_conn->ib_conn)
- iser_conn->ib_conn->iser_conn = NULL;
iscsi_conn_teardown(cls_conn);
+ /*
+ * Userspace will normally call the stop callback and
+ * already have freed the ib_conn, but if it goofed up then
+ * we free it here.
+ */
+ if (ib_conn) {
+ ib_conn->iser_conn = NULL;
+ iser_conn_put(ib_conn);
+ }
}
static int
@@ -340,12 +348,29 @@ iscsi_iser_conn_bind(struct iscsi_cls_session *cls_session,
iser_conn = conn->dd_data;
ib_conn->iser_conn = iser_conn;
iser_conn->ib_conn = ib_conn;
+ iser_conn_get(ib_conn);
conn->recv_lock = &iser_conn->lock;
return 0;
}
+static void
+iscsi_iser_conn_stop(struct iscsi_cls_conn *cls_conn, int flag)
+{
+ struct iscsi_conn *conn = cls_conn->dd_data;
+ struct iscsi_iser_conn *iser_conn = conn->dd_data;
+ struct iser_conn *ib_conn = iser_conn->ib_conn;
+
+ iscsi_conn_stop(cls_conn, flag);
+ /*
+ * There is no unbind event so the stop callback
+ * must release the ref from the bind.
+ */
+ iser_conn_put(ib_conn);
+ iser_conn->ib_conn = NULL;
+}
+
static int
iscsi_iser_conn_start(struct iscsi_cls_conn *cls_conn)
{
@@ -564,6 +589,17 @@ iscsi_iser_ep_disconnect(__u64 ep_handle)
if (!ib_conn)
return;
+ if (ib_conn->iser_conn)
+ /*
+ * Must suspend xmit path if the ep is bound to the
+ * iscsi_conn, so we know we are not accessing the ib_conn
+ * when we free it.
+ *
+ * This may not be bound if the ep poll failed.
+ */
+ iscsi_suspend_tx(ib_conn->iser_conn->iscsi_conn);
+
+
iser_err("ib conn %p state %d\n",ib_conn, ib_conn->state);
iser_conn_terminate(ib_conn);
}
@@ -622,7 +658,7 @@ static struct iscsi_transport iscsi_iser_transport = {
.get_conn_param = iscsi_conn_get_param,
.get_session_param = iscsi_session_get_param,
.start_conn = iscsi_iser_conn_start,
- .stop_conn = iscsi_conn_stop,
+ .stop_conn = iscsi_iser_conn_stop,
/* iscsi host params */
.get_host_param = iscsi_host_get_param,
.set_host_param = iscsi_host_set_param,