summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Smart <james.smart@emulex.com>2014-09-03 16:57:19 (GMT)
committerChristoph Hellwig <hch@lst.de>2014-09-16 16:10:10 (GMT)
commit12838e74f5164054fd7d5f5201a846ebb9755471 (patch)
treebc4a17eba4e0670723735ebf1701ea0bcc97ef58
parent2f6fa2c911167e7a3fda130689a36f55b39ed86d (diff)
downloadlinux-12838e74f5164054fd7d5f5201a846ebb9755471.tar.xz
lpfc: fix race between LOGO/PLOGI handling causing NULL pointer
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>
-rw-r--r--drivers/scsi/lpfc/lpfc_disc.h6
-rw-r--r--drivers/scsi/lpfc/lpfc_els.c7
-rw-r--r--drivers/scsi/lpfc/lpfc_hbadisc.c19
3 files changed, 30 insertions, 2 deletions
diff --git a/drivers/scsi/lpfc/lpfc_disc.h b/drivers/scsi/lpfc/lpfc_disc.h
index 1a6fe52..6977027 100644
--- a/drivers/scsi/lpfc/lpfc_disc.h
+++ b/drivers/scsi/lpfc/lpfc_disc.h
@@ -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) \
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
index 30ec80f..9d03e72 100644
--- a/drivers/scsi/lpfc/lpfc_els.c
+++ b/drivers/scsi/lpfc/lpfc_els.c
@@ -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;
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
index d178aee..2d929a5 100644
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -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)