The driver currently uses the ndlp to get the local rport which is
then used to get the nvme transport remoteport pointer. There can
be cases where a stale remoteport pointer is obtained as
synchronization isn't done through the different dereferences.

Correct by using locks to synchronize the dereferences.

Signed-off-by: Dick Kennedy <dick.kenn...@broadcom.com>
Signed-off-by: James Smart <jsmart2...@gmail.com>

---
v2:
  Needed to reinit nrport to NULL at start of every ndlp check
---
 drivers/scsi/lpfc/lpfc_attr.c    | 15 ++++++++++-----
 drivers/scsi/lpfc/lpfc_debugfs.c | 10 +++++-----
 drivers/scsi/lpfc/lpfc_nvme.c    | 11 ++++++++---
 3 files changed, 23 insertions(+), 13 deletions(-)

diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c
index 0169cd406518..dda7f450b96d 100644
--- a/drivers/scsi/lpfc/lpfc_attr.c
+++ b/drivers/scsi/lpfc/lpfc_attr.c
@@ -360,12 +360,12 @@ lpfc_nvme_info_show(struct device *dev, struct 
device_attribute *attr,
                goto buffer_done;
 
        list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
+               nrport = NULL;
+               spin_lock(&vport->phba->hbalock);
                rport = lpfc_ndlp_get_nrport(ndlp);
-               if (!rport)
-                       continue;
-
-               /* local short-hand pointer. */
-               nrport = rport->remoteport;
+               if (rport)
+                       nrport = rport->remoteport;
+               spin_unlock(&vport->phba->hbalock);
                if (!nrport)
                        continue;
 
@@ -3386,6 +3386,7 @@ lpfc_update_rport_devloss_tmo(struct lpfc_vport *vport)
        struct lpfc_nodelist  *ndlp;
 #if (IS_ENABLED(CONFIG_NVME_FC))
        struct lpfc_nvme_rport *rport;
+       struct nvme_fc_remote_port *remoteport = NULL;
 #endif
 
        shost = lpfc_shost_from_vport(vport);
@@ -3396,8 +3397,12 @@ lpfc_update_rport_devloss_tmo(struct lpfc_vport *vport)
                if (ndlp->rport)
                        ndlp->rport->dev_loss_tmo = vport->cfg_devloss_tmo;
 #if (IS_ENABLED(CONFIG_NVME_FC))
+               spin_lock(&vport->phba->hbalock);
                rport = lpfc_ndlp_get_nrport(ndlp);
                if (rport)
+                       remoteport = rport->remoteport;
+               spin_unlock(&vport->phba->hbalock);
+               if (remoteport)
                        nvme_fc_set_remoteport_devloss(rport->remoteport,
                                                       vport->cfg_devloss_tmo);
 #endif
diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c
index 9df0c051349f..aec5b10a8c85 100644
--- a/drivers/scsi/lpfc/lpfc_debugfs.c
+++ b/drivers/scsi/lpfc/lpfc_debugfs.c
@@ -551,7 +551,7 @@ lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char 
*buf, int size)
        unsigned char *statep;
        struct nvme_fc_local_port *localport;
        struct lpfc_nvmet_tgtport *tgtp;
-       struct nvme_fc_remote_port *nrport;
+       struct nvme_fc_remote_port *nrport = NULL;
        struct lpfc_nvme_rport *rport;
 
        cnt = (LPFC_NODELIST_SIZE / LPFC_NODELIST_ENTRY_SIZE);
@@ -696,11 +696,11 @@ lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char 
*buf, int size)
        len += snprintf(buf + len, size - len, "\tRport List:\n");
        list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
                /* local short-hand pointer. */
+               spin_lock(&phba->hbalock);
                rport = lpfc_ndlp_get_nrport(ndlp);
-               if (!rport)
-                       continue;
-
-               nrport = rport->remoteport;
+               if (rport)
+                       nrport = rport->remoteport;
+               spin_unlock(&phba->hbalock);
                if (!nrport)
                        continue;
 
diff --git a/drivers/scsi/lpfc/lpfc_nvme.c b/drivers/scsi/lpfc/lpfc_nvme.c
index 543873232d5a..23343a65530c 100644
--- a/drivers/scsi/lpfc/lpfc_nvme.c
+++ b/drivers/scsi/lpfc/lpfc_nvme.c
@@ -2718,7 +2718,9 @@ lpfc_nvme_register_port(struct lpfc_vport *vport, struct 
lpfc_nodelist *ndlp)
        rpinfo.port_name = wwn_to_u64(ndlp->nlp_portname.u.wwn);
        rpinfo.node_name = wwn_to_u64(ndlp->nlp_nodename.u.wwn);
 
+       spin_lock_irq(&vport->phba->hbalock);
        oldrport = lpfc_ndlp_get_nrport(ndlp);
+       spin_unlock_irq(&vport->phba->hbalock);
        if (!oldrport)
                lpfc_nlp_get(ndlp);
 
@@ -2833,7 +2835,7 @@ lpfc_nvme_unregister_port(struct lpfc_vport *vport, 
struct lpfc_nodelist *ndlp)
        struct nvme_fc_local_port *localport;
        struct lpfc_nvme_lport *lport;
        struct lpfc_nvme_rport *rport;
-       struct nvme_fc_remote_port *remoteport;
+       struct nvme_fc_remote_port *remoteport = NULL;
 
        localport = vport->localport;
 
@@ -2847,11 +2849,14 @@ lpfc_nvme_unregister_port(struct lpfc_vport *vport, 
struct lpfc_nodelist *ndlp)
        if (!lport)
                goto input_err;
 
+       spin_lock_irq(&vport->phba->hbalock);
        rport = lpfc_ndlp_get_nrport(ndlp);
-       if (!rport)
+       if (rport)
+               remoteport = rport->remoteport;
+       spin_unlock_irq(&vport->phba->hbalock);
+       if (!remoteport)
                goto input_err;
 
-       remoteport = rport->remoteport;
        lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_DISC,
                         "6033 Unreg nvme remoteport %p, portname x%llx, "
                         "port_id x%06x, portstate x%x port type x%x\n",
-- 
2.13.1

Reply via email to