From f7ac4eb8701bf0615c04004d90c198a5c2271a54 Mon Sep 17 00:00:00 2001 From: Daniel Wagner Date: Mar 28 2024 14:37:56 +0000 Subject: scsi: lpfc: Release hbalock before calling lpfc_worker_wake_up() (bsc#1221777). --- diff --git a/patches.suse/scsi-lpfc-Release-hbalock-before-calling-lpfc_worker.patch b/patches.suse/scsi-lpfc-Release-hbalock-before-calling-lpfc_worker.patch new file mode 100644 index 0000000..def4af4 --- /dev/null +++ b/patches.suse/scsi-lpfc-Release-hbalock-before-calling-lpfc_worker.patch @@ -0,0 +1,119 @@ +From: Justin Tee +Date: Tue, 5 Mar 2024 12:04:57 -0800 +Subject: scsi: lpfc: Release hbalock before calling lpfc_worker_wake_up() +Patch-mainline: Queued in subsystem maintainer repository +Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/mkp/scsi.git +Git-commit: ded20192dff31c91cef2a04f7e20e60e9bb887d3 +References: bsc#1221777 + +lpfc_worker_wake_up() calls the lpfc_work_done() routine, which takes the +hbalock. Thus, lpfc_worker_wake_up() should not be called while holding the +hbalock to avoid potential deadlock. + +Signed-off-by: Justin Tee +Link: https://lore.kernel.org/r/20240305200503.57317-7-justintee8345@gmail.com +Signed-off-by: Martin K. Petersen +Acked-by: Daniel Wagner +--- + drivers/scsi/lpfc/lpfc_els.c | 20 ++++++++++---------- + drivers/scsi/lpfc/lpfc_hbadisc.c | 5 ++--- + drivers/scsi/lpfc/lpfc_sli.c | 14 +++++++------- + 3 files changed, 19 insertions(+), 20 deletions(-) + +--- a/drivers/scsi/lpfc/lpfc_els.c ++++ b/drivers/scsi/lpfc/lpfc_els.c +@@ -4437,23 +4437,23 @@ lpfc_els_retry_delay(struct timer_list * + unsigned long flags; + struct lpfc_work_evt *evtp = &ndlp->els_retry_evt; + ++ /* Hold a node reference for outstanding queued work */ ++ if (!lpfc_nlp_get(ndlp)) ++ return; ++ + spin_lock_irqsave(&phba->hbalock, flags); + if (!list_empty(&evtp->evt_listp)) { + spin_unlock_irqrestore(&phba->hbalock, flags); ++ lpfc_nlp_put(ndlp); + return; + } + +- /* We need to hold the node by incrementing the reference +- * count until the queued work is done +- */ +- evtp->evt_arg1 = lpfc_nlp_get(ndlp); +- if (evtp->evt_arg1) { +- evtp->evt = LPFC_EVT_ELS_RETRY; +- list_add_tail(&evtp->evt_listp, &phba->work_list); +- lpfc_worker_wake_up(phba); +- } ++ evtp->evt_arg1 = ndlp; ++ evtp->evt = LPFC_EVT_ELS_RETRY; ++ list_add_tail(&evtp->evt_listp, &phba->work_list); + spin_unlock_irqrestore(&phba->hbalock, flags); +- return; ++ ++ lpfc_worker_wake_up(phba); + } + + /** +--- a/drivers/scsi/lpfc/lpfc_hbadisc.c ++++ b/drivers/scsi/lpfc/lpfc_hbadisc.c +@@ -257,7 +257,9 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport + if (evtp->evt_arg1) { + evtp->evt = LPFC_EVT_DEV_LOSS; + list_add_tail(&evtp->evt_listp, &phba->work_list); ++ spin_unlock_irqrestore(&phba->hbalock, iflags); + lpfc_worker_wake_up(phba); ++ return; + } + spin_unlock_irqrestore(&phba->hbalock, iflags); + } else { +@@ -275,10 +277,7 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport + lpfc_disc_state_machine(vport, ndlp, NULL, + NLP_EVT_DEVICE_RM); + } +- + } +- +- return; + } + + /** +--- a/drivers/scsi/lpfc/lpfc_sli.c ++++ b/drivers/scsi/lpfc/lpfc_sli.c +@@ -1217,9 +1217,9 @@ lpfc_set_rrq_active(struct lpfc_hba *phb + empty = list_empty(&phba->active_rrq_list); + list_add_tail(&rrq->list, &phba->active_rrq_list); + phba->hba_flag |= HBA_RRQ_ACTIVE; ++ spin_unlock_irqrestore(&phba->hbalock, iflags); + if (empty) + lpfc_worker_wake_up(phba); +- spin_unlock_irqrestore(&phba->hbalock, iflags); + return 0; + out: + spin_unlock_irqrestore(&phba->hbalock, iflags); +@@ -11373,18 +11373,18 @@ lpfc_sli_post_recovery_event(struct lpfc + unsigned long iflags; + struct lpfc_work_evt *evtp = &ndlp->recovery_evt; + ++ /* Hold a node reference for outstanding queued work */ ++ if (!lpfc_nlp_get(ndlp)) ++ return; ++ + spin_lock_irqsave(&phba->hbalock, iflags); + if (!list_empty(&evtp->evt_listp)) { + spin_unlock_irqrestore(&phba->hbalock, iflags); ++ lpfc_nlp_put(ndlp); + return; + } + +- /* Incrementing the reference count until the queued work is done. */ +- evtp->evt_arg1 = lpfc_nlp_get(ndlp); +- if (!evtp->evt_arg1) { +- spin_unlock_irqrestore(&phba->hbalock, iflags); +- return; +- } ++ evtp->evt_arg1 = ndlp; + evtp->evt = LPFC_EVT_RECOVER_PORT; + list_add_tail(&evtp->evt_listp, &phba->work_list); + spin_unlock_irqrestore(&phba->hbalock, iflags); diff --git a/series.conf b/series.conf index e078aa3..31c9084 100644 --- a/series.conf +++ b/series.conf @@ -20073,6 +20073,7 @@ patches.suse/scsi-lpfc-Remove-IRQF_ONESHOT-flag-from-threaded-IRQ.patch patches.suse/scsi-lpfc-Update-lpfc_ramp_down_queue_handler-logic.patch patches.suse/scsi-lpfc-Replace-hbalock-with-ndlp-lock-in-lpfc_nvm.patch + patches.suse/scsi-lpfc-Release-hbalock-before-calling-lpfc_worker.patch ######################################################## # end of sorted patches