scsi: iscsi: Rel ref after iscsi_lookup_endpoint()
authorMike Christie <michael.christie@oracle.com>
Tue, 25 May 2021 18:17:59 +0000 (13:17 -0500)
committerMartin K. Petersen <martin.petersen@oracle.com>
Wed, 2 Jun 2021 05:28:20 +0000 (01:28 -0400)
Subsequent commits allow the kernel to do ep_disconnect. In that case we
will have to get a proper refcount on the ep so one thread does not delete
it from under another.

Link: https://lore.kernel.org/r/20210525181821.7617-7-michael.christie@oracle.com
Reviewed-by: Lee Duncan <lduncan@suse.com>
Signed-off-by: Mike Christie <michael.christie@oracle.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/infiniband/ulp/iser/iscsi_iser.c
drivers/scsi/be2iscsi/be_iscsi.c
drivers/scsi/bnx2i/bnx2i_iscsi.c
drivers/scsi/cxgbi/libcxgbi.c
drivers/scsi/qedi/qedi_iscsi.c
drivers/scsi/qla4xxx/ql4_os.c
drivers/scsi/scsi_transport_iscsi.c
include/scsi/scsi_transport_iscsi.h

index 6baebcb..776e46e 100644 (file)
@@ -506,6 +506,7 @@ iscsi_iser_conn_bind(struct iscsi_cls_session *cls_session,
        iser_conn->iscsi_conn = conn;
 
 out:
+       iscsi_put_endpoint(ep);
        mutex_unlock(&iser_conn->state_mutex);
        return error;
 }
index 51a7b19..8aeaddc 100644 (file)
@@ -182,6 +182,7 @@ int beiscsi_conn_bind(struct iscsi_cls_session *cls_session,
        struct beiscsi_endpoint *beiscsi_ep;
        struct iscsi_endpoint *ep;
        uint16_t cri_index;
+       int rc = 0;
 
        ep = iscsi_lookup_endpoint(transport_fd);
        if (!ep)
@@ -189,15 +190,17 @@ int beiscsi_conn_bind(struct iscsi_cls_session *cls_session,
 
        beiscsi_ep = ep->dd_data;
 
-       if (iscsi_conn_bind(cls_session, cls_conn, is_leading))
-               return -EINVAL;
+       if (iscsi_conn_bind(cls_session, cls_conn, is_leading)) {
+               rc = -EINVAL;
+               goto put_ep;
+       }
 
        if (beiscsi_ep->phba != phba) {
                beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,
                            "BS_%d : beiscsi_ep->hba=%p not equal to phba=%p\n",
                            beiscsi_ep->phba, phba);
-
-               return -EEXIST;
+               rc = -EEXIST;
+               goto put_ep;
        }
        cri_index = BE_GET_CRI_FROM_CID(beiscsi_ep->ep_cid);
        if (phba->conn_table[cri_index]) {
@@ -209,7 +212,8 @@ int beiscsi_conn_bind(struct iscsi_cls_session *cls_session,
                                      beiscsi_ep->ep_cid,
                                      beiscsi_conn,
                                      phba->conn_table[cri_index]);
-                       return -EINVAL;
+                       rc = -EINVAL;
+                       goto put_ep;
                }
        }
 
@@ -226,7 +230,10 @@ int beiscsi_conn_bind(struct iscsi_cls_session *cls_session,
                    "BS_%d : cid %d phba->conn_table[%u]=%p\n",
                    beiscsi_ep->ep_cid, cri_index, beiscsi_conn);
        phba->conn_table[cri_index] = beiscsi_conn;
-       return 0;
+
+put_ep:
+       iscsi_put_endpoint(ep);
+       return rc;
 }
 
 static int beiscsi_iface_create_ipv4(struct beiscsi_hba *phba)
index 9a4f477..26cb1c6 100644 (file)
@@ -1420,17 +1420,23 @@ static int bnx2i_conn_bind(struct iscsi_cls_session *cls_session,
         * Forcefully terminate all in progress connection recovery at the
         * earliest, either in bind(), send_pdu(LOGIN), or conn_start()
         */
-       if (bnx2i_adapter_ready(hba))
-               return -EIO;
+       if (bnx2i_adapter_ready(hba)) {
+               ret_code = -EIO;
+               goto put_ep;
+       }
 
        bnx2i_ep = ep->dd_data;
        if ((bnx2i_ep->state == EP_STATE_TCP_FIN_RCVD) ||
-           (bnx2i_ep->state == EP_STATE_TCP_RST_RCVD))
+           (bnx2i_ep->state == EP_STATE_TCP_RST_RCVD)) {
                /* Peer disconnect via' FIN or RST */
-               return -EINVAL;
+               ret_code = -EINVAL;
+               goto put_ep;
+       }
 
-       if (iscsi_conn_bind(cls_session, cls_conn, is_leading))
-               return -EINVAL;
+       if (iscsi_conn_bind(cls_session, cls_conn, is_leading)) {
+               ret_code = -EINVAL;
+               goto put_ep;
+       }
 
        if (bnx2i_ep->hba != hba) {
                /* Error - TCP connection does not belong to this device
@@ -1441,7 +1447,8 @@ static int bnx2i_conn_bind(struct iscsi_cls_session *cls_session,
                iscsi_conn_printk(KERN_ALERT, cls_conn->dd_data,
                                  "belong to hba (%s)\n",
                                  hba->netdev->name);
-               return -EEXIST;
+               ret_code = -EEXIST;
+               goto put_ep;
        }
        bnx2i_ep->conn = bnx2i_conn;
        bnx2i_conn->ep = bnx2i_ep;
@@ -1458,6 +1465,8 @@ static int bnx2i_conn_bind(struct iscsi_cls_session *cls_session,
                bnx2i_put_rq_buf(bnx2i_conn, 0);
 
        bnx2i_arm_cq_event_coalescing(bnx2i_conn->ep, CNIC_ARM_CQE);
+put_ep:
+       iscsi_put_endpoint(ep);
        return ret_code;
 }
 
index 215dd0e..dbe22a7 100644 (file)
@@ -2690,11 +2690,13 @@ int cxgbi_bind_conn(struct iscsi_cls_session *cls_session,
        err = csk->cdev->csk_ddp_setup_pgidx(csk, csk->tid,
                                             ppm->tformat.pgsz_idx_dflt);
        if (err < 0)
-               return err;
+               goto put_ep;
 
        err = iscsi_conn_bind(cls_session, cls_conn, is_leading);
-       if (err)
-               return -EINVAL;
+       if (err) {
+               err = -EINVAL;
+               goto put_ep;
+       }
 
        /*  calculate the tag idx bits needed for this conn based on cmds_max */
        cconn->task_idx_bits = (__ilog2_u32(conn->session->cmds_max - 1)) + 1;
@@ -2715,7 +2717,9 @@ int cxgbi_bind_conn(struct iscsi_cls_session *cls_session,
        /*  init recv engine */
        iscsi_tcp_hdr_recv_prep(tcp_conn);
 
-       return 0;
+put_ep:
+       iscsi_put_endpoint(ep);
+       return err;
 }
 EXPORT_SYMBOL_GPL(cxgbi_bind_conn);
 
index 30dc345..80f8d35 100644 (file)
@@ -377,6 +377,7 @@ static int qedi_conn_bind(struct iscsi_cls_session *cls_session,
        struct qedi_ctx *qedi = iscsi_host_priv(shost);
        struct qedi_endpoint *qedi_ep;
        struct iscsi_endpoint *ep;
+       int rc = 0;
 
        ep = iscsi_lookup_endpoint(transport_fd);
        if (!ep)
@@ -384,11 +385,16 @@ static int qedi_conn_bind(struct iscsi_cls_session *cls_session,
 
        qedi_ep = ep->dd_data;
        if ((qedi_ep->state == EP_STATE_TCP_FIN_RCVD) ||
-           (qedi_ep->state == EP_STATE_TCP_RST_RCVD))
-               return -EINVAL;
+           (qedi_ep->state == EP_STATE_TCP_RST_RCVD)) {
+               rc = -EINVAL;
+               goto put_ep;
+       }
+
+       if (iscsi_conn_bind(cls_session, cls_conn, is_leading)) {
+               rc = -EINVAL;
+               goto put_ep;
+       }
 
-       if (iscsi_conn_bind(cls_session, cls_conn, is_leading))
-               return -EINVAL;
 
        qedi_ep->conn = qedi_conn;
        qedi_conn->ep = qedi_ep;
@@ -398,13 +404,18 @@ static int qedi_conn_bind(struct iscsi_cls_session *cls_session,
        qedi_conn->cmd_cleanup_req = 0;
        qedi_conn->cmd_cleanup_cmpl = 0;
 
-       if (qedi_bind_conn_to_iscsi_cid(qedi, qedi_conn))
-               return -EINVAL;
+       if (qedi_bind_conn_to_iscsi_cid(qedi, qedi_conn)) {
+               rc = -EINVAL;
+               goto put_ep;
+       }
+
 
        spin_lock_init(&qedi_conn->tmf_work_lock);
        INIT_LIST_HEAD(&qedi_conn->tmf_work_list);
        init_waitqueue_head(&qedi_conn->wait_queue);
-       return 0;
+put_ep:
+       iscsi_put_endpoint(ep);
+       return rc;
 }
 
 static int qedi_iscsi_update_conn(struct qedi_ctx *qedi,
index 74d0d1b..0e7a7e8 100644 (file)
@@ -3235,6 +3235,7 @@ static int qla4xxx_conn_bind(struct iscsi_cls_session *cls_session,
        conn = cls_conn->dd_data;
        qla_conn = conn->dd_data;
        qla_conn->qla_ep = ep->dd_data;
+       iscsi_put_endpoint(ep);
        return 0;
 }
 
index 2eb77f6..bab6654 100644 (file)
@@ -266,9 +266,20 @@ void iscsi_destroy_endpoint(struct iscsi_endpoint *ep)
 }
 EXPORT_SYMBOL_GPL(iscsi_destroy_endpoint);
 
+void iscsi_put_endpoint(struct iscsi_endpoint *ep)
+{
+       put_device(&ep->dev);
+}
+EXPORT_SYMBOL_GPL(iscsi_put_endpoint);
+
+/**
+ * iscsi_lookup_endpoint - get ep from handle
+ * @handle: endpoint handle
+ *
+ * Caller must do a iscsi_put_endpoint.
+ */
 struct iscsi_endpoint *iscsi_lookup_endpoint(u64 handle)
 {
-       struct iscsi_endpoint *ep;
        struct device *dev;
 
        dev = class_find_device(&iscsi_endpoint_class, NULL, &handle,
@@ -276,13 +287,7 @@ struct iscsi_endpoint *iscsi_lookup_endpoint(u64 handle)
        if (!dev)
                return NULL;
 
-       ep = iscsi_dev_to_endpoint(dev);
-       /*
-        * we can drop this now because the interface will prevent
-        * removals and lookups from racing.
-        */
-       put_device(dev);
-       return ep;
+       return iscsi_dev_to_endpoint(dev);
 }
 EXPORT_SYMBOL_GPL(iscsi_lookup_endpoint);
 
@@ -2990,6 +2995,7 @@ static int iscsi_if_ep_disconnect(struct iscsi_transport *transport,
        }
 
        transport->ep_disconnect(ep);
+       iscsi_put_endpoint(ep);
        return 0;
 }
 
@@ -3015,6 +3021,7 @@ iscsi_if_transport_ep(struct iscsi_transport *transport,
 
                ev->r.retcode = transport->ep_poll(ep,
                                                   ev->u.ep_poll.timeout_ms);
+               iscsi_put_endpoint(ep);
                break;
        case ISCSI_UEVENT_TRANSPORT_EP_DISCONNECT:
                rc = iscsi_if_ep_disconnect(transport,
@@ -3698,6 +3705,7 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group)
                                        ev->u.c_bound_session.initial_cmdsn,
                                        ev->u.c_bound_session.cmds_max,
                                        ev->u.c_bound_session.queue_depth);
+               iscsi_put_endpoint(ep);
                break;
        case ISCSI_UEVENT_DESTROY_SESSION:
                session = iscsi_session_lookup(ev->u.d_session.sid);
@@ -3769,6 +3777,7 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group)
                        mutex_lock(&conn->ep_mutex);
                        conn->ep = ep;
                        mutex_unlock(&conn->ep_mutex);
+                       iscsi_put_endpoint(ep);
                } else
                        iscsi_cls_conn_printk(KERN_ERR, conn,
                                              "Could not set ep conn "
index 8874016..d36a72c 100644 (file)
@@ -442,6 +442,7 @@ extern int iscsi_scan_finished(struct Scsi_Host *shost, unsigned long time);
 extern struct iscsi_endpoint *iscsi_create_endpoint(int dd_size);
 extern void iscsi_destroy_endpoint(struct iscsi_endpoint *ep);
 extern struct iscsi_endpoint *iscsi_lookup_endpoint(u64 handle);
+extern void iscsi_put_endpoint(struct iscsi_endpoint *ep);
 extern int iscsi_block_scsi_eh(struct scsi_cmnd *cmd);
 extern struct iscsi_iface *iscsi_create_iface(struct Scsi_Host *shost,
                                              struct iscsi_transport *t,