IB/srpt: Fix srpt_cm_req_recv() error path (1/2)
authorBart Van Assche <bart.vanassche@wdc.com>
Tue, 10 Jul 2018 17:31:58 +0000 (10:31 -0700)
committerJason Gunthorpe <jgg@mellanox.com>
Fri, 13 Jul 2018 17:55:32 +0000 (11:55 -0600)
Once a target session has been allocated, if an error occurs, the session
must be freed. Since it is not safe to call blocking code from the context
of an connection manager callback, trigger target session release in this
case by calling srpt_close_ch().

Fixes: db7683d7deb2 ("IB/srpt: Fix login-related race conditions")
Signed-off-by: Bart Van Assche <bart.vanassche@wdc.com>
Cc: <stable@vger.kernel.org>
Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
drivers/infiniband/ulp/srpt/ib_srpt.c

index 3cb99ca..6b86f5c 100644 (file)
@@ -2087,7 +2087,7 @@ static int srpt_cm_req_recv(struct srpt_device *const sdev,
                struct rdma_conn_param rdma_cm;
                struct ib_cm_rep_param ib_cm;
        } *rep_param = NULL;
-       struct srpt_rdma_ch *ch;
+       struct srpt_rdma_ch *ch = NULL;
        char i_port_id[36];
        u32 it_iu_len;
        int i, ret;
@@ -2234,13 +2234,15 @@ static int srpt_cm_req_recv(struct srpt_device *const sdev,
                                                TARGET_PROT_NORMAL,
                                                i_port_id + 2, ch, NULL);
        if (IS_ERR_OR_NULL(ch->sess)) {
+               WARN_ON_ONCE(ch->sess == NULL);
                ret = PTR_ERR(ch->sess);
+               ch->sess = NULL;
                pr_info("Rejected login for initiator %s: ret = %d.\n",
                        ch->sess_name, ret);
                rej->reason = cpu_to_be32(ret == -ENOMEM ?
                                SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES :
                                SRP_LOGIN_REJ_CHANNEL_LIMIT_REACHED);
-               goto reject;
+               goto destroy_ib;
        }
 
        mutex_lock(&sport->mutex);
@@ -2279,7 +2281,7 @@ static int srpt_cm_req_recv(struct srpt_device *const sdev,
                rej->reason = cpu_to_be32(SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES);
                pr_err("rejected SRP_LOGIN_REQ because enabling RTR failed (error code = %d)\n",
                       ret);
-               goto destroy_ib;
+               goto reject;
        }
 
        pr_debug("Establish connection sess=%p name=%s ch=%p\n", ch->sess,
@@ -2379,6 +2381,15 @@ reject:
                ib_send_cm_rej(ib_cm_id, IB_CM_REJ_CONSUMER_DEFINED, NULL, 0,
                               rej, sizeof(*rej));
 
+       if (ch && ch->sess) {
+               srpt_close_ch(ch);
+               /*
+                * Tell the caller not to free cm_id since
+                * srpt_release_channel_work() will do that.
+                */
+               ret = 0;
+       }
+
 out:
        kfree(rep_param);
        kfree(rsp);