diff options
author | James Smart <james.smart@emulex.com> | 2014-09-03 20:57:19 +0400 |
---|---|---|
committer | Christoph Hellwig <hch@lst.de> | 2014-09-16 20:10:10 +0400 |
commit | 12838e74f5164054fd7d5f5201a846ebb9755471 (patch) | |
tree | bc4a17eba4e0670723735ebf1701ea0bcc97ef58 /drivers/scsi/lpfc | |
parent | 2f6fa2c911167e7a3fda130689a36f55b39ed86d (diff) | |
download | linux-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>
Diffstat (limited to 'drivers/scsi/lpfc')
-rw-r--r-- | drivers/scsi/lpfc/lpfc_disc.h | 6 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_els.c | 7 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_hbadisc.c | 19 |
3 files changed, 30 insertions, 2 deletions
diff --git a/drivers/scsi/lpfc/lpfc_disc.h b/drivers/scsi/lpfc/lpfc_disc.h index 1a6fe524940d..6977027979be 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 30ec80f32d1a..9d03e7250fb4 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 d178aee02b49..2d929a5e8354 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) |