lpfc: fix race between LOGO/PLOGI handling causing NULL pointer
authorJames Smart <james.smart@emulex.com>
Wed, 3 Sep 2014 16:57:19 +0000 (12:57 -0400)
committerChristoph Hellwig <hch@lst.de>
Tue, 16 Sep 2014 16:10:10 +0000 (09:10 -0700)
Fix race between LOGO/PLOGI handling causing NULL pointer

Signed-off-by: James Smart <james.smart@emulex.com>
Signed-off-by: Dick Kennedy <dick.kennedy@emulex.com>
Signed-off-by: Christoph Hellwig <hch@lst.de>
drivers/scsi/lpfc/lpfc_disc.h
drivers/scsi/lpfc/lpfc_els.c
drivers/scsi/lpfc/lpfc_hbadisc.c

index 1a6fe524940d6a6ccafc8addf4ec2a561cb40198..6977027979beb6be433adad4cf9211c7787ba214 100644 (file)
@@ -78,7 +78,8 @@ struct lpfc_nodelist {
        struct list_head nlp_listp;
        struct lpfc_name nlp_portname;
        struct lpfc_name nlp_nodename;
-       uint32_t         nlp_flag;              /* entry  flags */
+       uint32_t         nlp_flag;              /* entry flags */
+       uint32_t         nlp_add_flag;          /* additional flags */
        uint32_t         nlp_DID;               /* FC D_ID of entry */
        uint32_t         nlp_last_elscmd;       /* Last ELS cmd sent */
        uint16_t         nlp_type;
@@ -157,6 +158,9 @@ struct lpfc_node_rrq {
 #define NLP_FIRSTBURST     0x40000000  /* Target supports FirstBurst */
 #define NLP_RPI_REGISTERED 0x80000000  /* nlp_rpi is valid */
 
+/* Defines for nlp_add_flag (uint32) */
+#define NLP_IN_DEV_LOSS  0x00000001    /* Dev Loss processing in progress */
+
 /* ndlp usage management macros */
 #define NLP_CHK_NODE_ACT(ndlp)         (((ndlp)->nlp_usg_map \
                                                & NLP_USG_NODE_ACT_BIT) \
index 30ec80f32d1abdcc0867b5a695d61fabd399a41a..9d03e7250fb45a6d2c8e8d0dae003f9eaadfea64 100644 (file)
@@ -6693,6 +6693,13 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 
        phba->fc_stat.elsRcvFrame++;
 
+       /*
+        * Do not process any unsolicited ELS commands
+        * if the ndlp is in DEV_LOSS
+        */
+       if (ndlp->nlp_add_flag & NLP_IN_DEV_LOSS)
+               goto dropit;
+
        elsiocb->context1 = lpfc_nlp_get(ndlp);
        elsiocb->vport = vport;
 
index d178aee02b4911aeef246c4b1fc7c60eb2b530dd..2d929a5e8354dab11871d65e9b36bc22a5a333eb 100644 (file)
@@ -153,6 +153,16 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport)
                        put_device(&rport->dev);
                        return;
                }
+
+               put_node = rdata->pnode != NULL;
+               put_rport = ndlp->rport != NULL;
+               rdata->pnode = NULL;
+               ndlp->rport = NULL;
+               if (put_node)
+                       lpfc_nlp_put(ndlp);
+               if (put_rport)
+                       put_device(&rport->dev);
+               return;
        }
 
        evtp = &ndlp->dev_loss_evt;
@@ -161,6 +171,7 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport)
                return;
 
        evtp->evt_arg1  = lpfc_nlp_get(ndlp);
+       ndlp->nlp_add_flag |= NLP_IN_DEV_LOSS;
 
        spin_lock_irq(&phba->hbalock);
        /* We need to hold the node by incrementing the reference
@@ -201,8 +212,10 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
 
        rport = ndlp->rport;
 
-       if (!rport)
+       if (!rport) {
+               ndlp->nlp_add_flag &= ~NLP_IN_DEV_LOSS;
                return fcf_inuse;
+       }
 
        rdata = rport->dd_data;
        name = (uint8_t *) &ndlp->nlp_portname;
@@ -235,6 +248,7 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
                put_rport = ndlp->rport != NULL;
                rdata->pnode = NULL;
                ndlp->rport = NULL;
+               ndlp->nlp_add_flag &= ~NLP_IN_DEV_LOSS;
                if (put_node)
                        lpfc_nlp_put(ndlp);
                if (put_rport)
@@ -250,6 +264,7 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
                                 *name, *(name+1), *(name+2), *(name+3),
                                 *(name+4), *(name+5), *(name+6), *(name+7),
                                 ndlp->nlp_DID);
+               ndlp->nlp_add_flag &= ~NLP_IN_DEV_LOSS;
                return fcf_inuse;
        }
 
@@ -259,6 +274,7 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
                put_rport = ndlp->rport != NULL;
                rdata->pnode = NULL;
                ndlp->rport = NULL;
+               ndlp->nlp_add_flag &= ~NLP_IN_DEV_LOSS;
                if (put_node)
                        lpfc_nlp_put(ndlp);
                if (put_rport)
@@ -297,6 +313,7 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
        put_rport = ndlp->rport != NULL;
        rdata->pnode = NULL;
        ndlp->rport = NULL;
+       ndlp->nlp_add_flag &= ~NLP_IN_DEV_LOSS;
        if (put_node)
                lpfc_nlp_put(ndlp);
        if (put_rport)