scsi: lpfc: Validate hdwq pointers before dereferencing in reset/errata paths

BugLink: https://bugs.launchpad.net/bugs/2089884

[ Upstream commit 2be1d4f11944cd6283cb97268b3e17c4424945ca ]

When the HBA is undergoing a reset or is handling an errata event, NULL ptr
dereference crashes may occur in routines such as
lpfc_sli_flush_io_rings(), lpfc_dev_loss_tmo_callbk(), or
lpfc_abort_handler().

Add NULL ptr checks before dereferencing hdwq pointers that may have been
freed due to operations colliding with a reset or errata event handler.

Signed-off-by: Justin Tee <justin.tee@broadcom.com>
Link: https://lore.kernel.org/r/20240726231512.92867-4-justintee8345@gmail.com
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
[koichiroden: resolved conflict caused by missing commits:
e39811bec6b1 ("scsi: lpfc: Change lpfc_vport load_flag member into a bitmask")
e780c9423b10 ("scsi: lpfc: Change lpfc_hba hba_flag member into a bitmask")
and adjusted lpfc_printf_log fmt]
Signed-off-by: Koichiro Den <koichiro.den@canonical.com>
Signed-off-by: Roxana Nicolescu <roxana.nicolescu@canonical.com>
This commit is contained in:
Justin Tee
2024-07-26 16:15:07 -07:00
committed by Mehmet Basaran
parent c648ce0a46
commit 6cdd014885
3 changed files with 24 additions and 3 deletions
+2 -1
View File
@@ -175,7 +175,8 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport)
ndlp->nlp_state, ndlp->fc4_xpt_flags); ndlp->nlp_state, ndlp->fc4_xpt_flags);
/* Don't schedule a worker thread event if the vport is going down. */ /* Don't schedule a worker thread event if the vport is going down. */
if (vport->load_flag & FC_UNLOADING) { if ((vport->load_flag & FC_UNLOADING) ||
!(phba->hba_flag & HBA_SETUP)) {
spin_lock_irqsave(&ndlp->lock, iflags); spin_lock_irqsave(&ndlp->lock, iflags);
ndlp->rport = NULL; ndlp->rport = NULL;
+11 -2
View File
@@ -5546,11 +5546,20 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)
iocb = &lpfc_cmd->cur_iocbq; iocb = &lpfc_cmd->cur_iocbq;
if (phba->sli_rev == LPFC_SLI_REV4) { if (phba->sli_rev == LPFC_SLI_REV4) {
pring_s4 = phba->sli4_hba.hdwq[iocb->hba_wqidx].io_wq->pring; /* if the io_wq & pring are gone, the port was reset. */
if (!pring_s4) { if (!phba->sli4_hba.hdwq[iocb->hba_wqidx].io_wq ||
!phba->sli4_hba.hdwq[iocb->hba_wqidx].io_wq->pring) {
lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP,
"2877 SCSI Layer I/O Abort Request "
"IO CMPL Status x%x ID %d LUN %llu "
"HBA_SETUP %d\n", FAILED,
cmnd->device->id,
(u64)cmnd->device->lun,
(phba->hba_flag & HBA_SETUP));
ret = FAILED; ret = FAILED;
goto out_unlock_hba; goto out_unlock_hba;
} }
pring_s4 = phba->sli4_hba.hdwq[iocb->hba_wqidx].io_wq->pring;
spin_lock(&pring_s4->ring_lock); spin_lock(&pring_s4->ring_lock);
} }
/* the command is in process of being cancelled */ /* the command is in process of being cancelled */
+11
View File
@@ -4689,6 +4689,17 @@ lpfc_sli_flush_io_rings(struct lpfc_hba *phba)
/* Look on all the FCP Rings for the iotag */ /* Look on all the FCP Rings for the iotag */
if (phba->sli_rev >= LPFC_SLI_REV4) { if (phba->sli_rev >= LPFC_SLI_REV4) {
for (i = 0; i < phba->cfg_hdw_queue; i++) { for (i = 0; i < phba->cfg_hdw_queue; i++) {
if (!phba->sli4_hba.hdwq ||
!phba->sli4_hba.hdwq[i].io_wq) {
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
"7777 hdwq's deleted %x "
"%x %x %x\n",
phba->pport->load_flag,
phba->hba_flag,
phba->link_state,
phba->sli.sli_flag);
return;
}
pring = phba->sli4_hba.hdwq[i].io_wq->pring; pring = phba->sli4_hba.hdwq[i].io_wq->pring;
spin_lock_irq(&pring->ring_lock); spin_lock_irq(&pring->ring_lock);