From: James Smart Date: Mon, 9 Apr 2018 21:24:27 +0000 (-0700) Subject: scsi: lpfc: Fix NULL pointer access in lpfc_nvme_info_show X-Git-Tag: v5.15~8644^2~206 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=01466024d2de1c05652d69411461e8e7908f0d1e;p=platform%2Fkernel%2Flinux-starfive.git scsi: lpfc: Fix NULL pointer access in lpfc_nvme_info_show After making remoteport unregister requests, the ndlp nrport pointer was stale. Track when waiting for waiting for unregister completion callback and adjust nldp pointer assignment. Add a few safety checks for NULL pointer values. Signed-off-by: Dick Kennedy Signed-off-by: James Smart Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 15f921d..fd3b253 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -149,6 +149,7 @@ lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr, struct lpfc_nvmet_tgtport *tgtp; struct nvme_fc_local_port *localport; struct lpfc_nvme_lport *lport; + struct lpfc_nvme_rport *rport; struct lpfc_nodelist *ndlp; struct nvme_fc_remote_port *nrport; struct lpfc_nvme_ctrl_stat *cstat; @@ -312,11 +313,14 @@ lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr, localport->port_id, statep); list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { - if (!ndlp->nrport) + rport = lpfc_ndlp_get_nrport(ndlp); + if (!rport) continue; /* local short-hand pointer. */ - nrport = ndlp->nrport->remoteport; + nrport = rport->remoteport; + if (!nrport) + continue; /* Port state is only one of two values for now. */ switch (nrport->port_state) { @@ -3290,6 +3294,9 @@ lpfc_update_rport_devloss_tmo(struct lpfc_vport *vport) { struct Scsi_Host *shost; struct lpfc_nodelist *ndlp; +#if (IS_ENABLED(CONFIG_NVME_FC)) + struct lpfc_nvme_rport *rport; +#endif shost = lpfc_shost_from_vport(vport); spin_lock_irq(shost->host_lock); @@ -3299,8 +3306,9 @@ 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)) - if (ndlp->nrport) - nvme_fc_set_remoteport_devloss(ndlp->nrport->remoteport, + rport = lpfc_ndlp_get_nrport(ndlp); + if (rport) + 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 cd3eb6b..afe7883 100644 --- a/drivers/scsi/lpfc/lpfc_debugfs.c +++ b/drivers/scsi/lpfc/lpfc_debugfs.c @@ -552,6 +552,7 @@ lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size) struct nvme_fc_local_port *localport; struct lpfc_nvmet_tgtport *tgtp; struct nvme_fc_remote_port *nrport; + struct lpfc_nvme_rport *rport; cnt = (LPFC_NODELIST_SIZE / LPFC_NODELIST_ENTRY_SIZE); outio = 0; @@ -695,10 +696,13 @@ 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. */ - if (!ndlp->nrport) + rport = lpfc_ndlp_get_nrport(ndlp); + if (!rport) continue; - nrport = ndlp->nrport->remoteport; + nrport = rport->remoteport; + if (!nrport) + continue; /* Port state is only one of two values for now. */ switch (nrport->port_state) { diff --git a/drivers/scsi/lpfc/lpfc_nvme.c b/drivers/scsi/lpfc/lpfc_nvme.c index 1414c58..1cb2c63 100644 --- a/drivers/scsi/lpfc/lpfc_nvme.c +++ b/drivers/scsi/lpfc/lpfc_nvme.c @@ -335,6 +335,7 @@ lpfc_nvme_remoteport_delete(struct nvme_fc_remote_port *remoteport) remoteport); spin_lock_irq(&vport->phba->hbalock); ndlp->nrport = NULL; + ndlp->upcall_flags &= ~NLP_WAIT_FOR_UNREG; spin_unlock_irq(&vport->phba->hbalock); /* Remove original register reference. The host transport @@ -2646,6 +2647,7 @@ lpfc_nvme_register_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 lpfc_nvme_rport *oldrport; struct nvme_fc_remote_port *remote_port; struct nvme_fc_port_info rpinfo; struct lpfc_nodelist *prev_ndlp; @@ -2678,7 +2680,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); - if (!ndlp->nrport) + + oldrport = lpfc_ndlp_get_nrport(ndlp); + if (!oldrport) lpfc_nlp_get(ndlp); ret = nvme_fc_register_remoteport(localport, &rpinfo, &remote_port); @@ -2688,8 +2692,8 @@ lpfc_nvme_register_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) * new rport. */ rport = remote_port->private; - if (ndlp->nrport) { - if (ndlp->nrport == remote_port->private) { + if (oldrport) { + if (oldrport == remote_port->private) { /* Same remoteport. Just reuse. */ lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_NVME_DISC, @@ -2713,6 +2717,7 @@ lpfc_nvme_register_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) */ spin_lock_irq(&vport->phba->hbalock); ndlp->nrport = NULL; + ndlp->upcall_flags &= ~NLP_WAIT_FOR_UNREG; spin_unlock_irq(&vport->phba->hbalock); rport->ndlp = NULL; rport->remoteport = NULL; @@ -2785,7 +2790,7 @@ lpfc_nvme_unregister_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) if (!lport) goto input_err; - rport = ndlp->nrport; + rport = lpfc_ndlp_get_nrport(ndlp); if (!rport) goto input_err; diff --git a/drivers/scsi/lpfc/lpfc_nvme.h b/drivers/scsi/lpfc/lpfc_nvme.h index b07188b..5323697 100644 --- a/drivers/scsi/lpfc/lpfc_nvme.h +++ b/drivers/scsi/lpfc/lpfc_nvme.h @@ -30,6 +30,10 @@ #define LPFC_NVME_FB_SHIFT 9 #define LPFC_NVME_MAX_FB (1 << 20) /* 1M */ +#define lpfc_ndlp_get_nrport(ndlp) \ + ((!ndlp->nrport || (ndlp->upcall_flags & NLP_WAIT_FOR_UNREG)) \ + ? NULL : ndlp->nrport) + struct lpfc_nvme_qhandle { uint32_t index; /* WQ index to use */ uint32_t qidx; /* queue index passed to create */