OSDN Git Service

scsi: lpfc: Fix Oops in nvme_register with target logout/login
authorJames Smart <jsmart2021@gmail.com>
Wed, 14 Aug 2019 23:56:41 +0000 (16:56 -0700)
committerMartin K. Petersen <martin.petersen@oracle.com>
Tue, 20 Aug 2019 02:41:09 +0000 (22:41 -0400)
lpfc_nvme_register_port hit a null prev_ndlp pointer in a test with lots of
target ports swapping addresses. The oldport value was stale, thus it's
ndlp (prev_ndlp set to it) was used.

Fix by moving oldrport pointer checks, and if used prev_ndlp pointer
assignment, to be done while the lock is held.

Signed-off-by: Dick Kennedy <dick.kennedy@broadcom.com>
Signed-off-by: James Smart <jsmart2021@gmail.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/lpfc/lpfc_nvme.c

index 946642c..9746808 100644 (file)
@@ -2317,9 +2317,13 @@ lpfc_nvme_register_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
 
        spin_lock_irq(&vport->phba->hbalock);
        oldrport = lpfc_ndlp_get_nrport(ndlp);
-       spin_unlock_irq(&vport->phba->hbalock);
-       if (!oldrport)
+       if (oldrport) {
+               prev_ndlp = oldrport->ndlp;
+               spin_unlock_irq(&vport->phba->hbalock);
+       } else {
+               spin_unlock_irq(&vport->phba->hbalock);
                lpfc_nlp_get(ndlp);
+       }
 
        ret = nvme_fc_register_remoteport(localport, &rpinfo, &remote_port);
        if (!ret) {
@@ -2338,7 +2342,6 @@ lpfc_nvme_register_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
                        /* New remoteport record does not guarantee valid
                         * host private memory area.
                         */
-                       prev_ndlp = oldrport->ndlp;
                        if (oldrport == remote_port->private) {
                                /* Same remoteport - ndlp should match.
                                 * Just reuse.
@@ -2352,7 +2355,7 @@ lpfc_nvme_register_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
                                                 remote_port->port_name,
                                                 remote_port->port_id,
                                                 remote_port->port_role,
-                                                prev_ndlp,
+                                                oldrport->ndlp,
                                                 ndlp,
                                                 ndlp->nlp_type,
                                                 ndlp->nlp_DID);