scsi: lpfc: Fix possible ABBA deadlock in nvmet_xri_aborted()
authorJames Smart <jsmart2021@gmail.com>
Fri, 30 Jul 2021 16:33:09 +0000 (09:33 -0700)
committerMartin K. Petersen <martin.petersen@oracle.com>
Sat, 31 Jul 2021 03:47:19 +0000 (23:47 -0400)
The lpfc_sli4_nvmet_xri_aborted() routine takes out the abts_buf_list_lock
and traverses the buffer contexts to match the xri. Upon match, it then
takes the context lock before potentially removing the context from the
associated buffer list. This violates the lock hierarchy used elsewhere in
the driver of locking context, then the abts_buf_list_lock - thus a
possible deadlock.

Resolve by: after matching, release the abts_buf_list_lock, then take the
context lock, and if to be deleted from the list, retake the
abts_buf_list_lock, maintaining lock hierarchy. This matches same list lock
hierarchy as elsewhere in the driver

Link: https://lore.kernel.org/r/20210730163309.25809-1-jsmart2021@gmail.com
Reported-by: Jia-Ju Bai <baijiaju1990@gmail.com>
Signed-off-by: James Smart <jsmart2021@gmail.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/lpfc/lpfc_nvmet.c

index f2d9a3580887b9df4496939b3009e1e6ee86e6dc..6e3dd0b9bcfa96693d7c7e380de44a5b7ac82e84 100644 (file)
@@ -1797,19 +1797,22 @@ lpfc_sli4_nvmet_xri_aborted(struct lpfc_hba *phba,
                if (ctxp->ctxbuf->sglq->sli4_xritag != xri)
                        continue;
 
-               spin_lock(&ctxp->ctxlock);
+               spin_unlock_irqrestore(&phba->sli4_hba.abts_nvmet_buf_list_lock,
+                                      iflag);
+
+               spin_lock_irqsave(&ctxp->ctxlock, iflag);
                /* Check if we already received a free context call
                 * and we have completed processing an abort situation.
                 */
                if (ctxp->flag & LPFC_NVME_CTX_RLS &&
                    !(ctxp->flag & LPFC_NVME_ABORT_OP)) {
+                       spin_lock(&phba->sli4_hba.abts_nvmet_buf_list_lock);
                        list_del_init(&ctxp->list);
+                       spin_unlock(&phba->sli4_hba.abts_nvmet_buf_list_lock);
                        released = true;
                }
                ctxp->flag &= ~LPFC_NVME_XBUSY;
-               spin_unlock(&ctxp->ctxlock);
-               spin_unlock_irqrestore(&phba->sli4_hba.abts_nvmet_buf_list_lock,
-                                      iflag);
+               spin_unlock_irqrestore(&ctxp->ctxlock, iflag);
 
                rrq_empty = list_empty(&phba->active_rrq_list);
                ndlp = lpfc_findnode_did(phba->pport, ctxp->sid);