OSDN Git Service

scsi: lpfc: Fix SCSI io host reset causing kernel crash
authorJames Smart <jsmart2021@gmail.com>
Tue, 30 Jan 2018 23:58:57 +0000 (15:58 -0800)
committerMartin K. Petersen <martin.petersen@oracle.com>
Mon, 12 Feb 2018 16:43:23 +0000 (11:43 -0500)
During SCSI error handling escalation to host reset, the SCSI io
routines were moved off the txcmplq, but the individual io's ON_CMPLQ
flag wasn't cleared.  Thus, a background thread saw the io and attempted
to access it as if on the txcmplq.

Clear the flag upon removal.

Signed-off-by: Dick Kennedy <dick.kennedy@broadcom.com>
Signed-off-by: James Smart <james.smart@broadcom.com>
Reviewed-by: Hannes Reinecke <hare@suse.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/lpfc/lpfc_init.c
drivers/scsi/lpfc/lpfc_sli.c

index bff5c95..aa7872a 100644 (file)
@@ -958,6 +958,7 @@ lpfc_hba_clean_txcmplq(struct lpfc_hba *phba)
        struct lpfc_sli_ring *pring;
        LIST_HEAD(completions);
        int i;
+       struct lpfc_iocbq *piocb, *next_iocb;
 
        if (phba->sli_rev != LPFC_SLI_REV4) {
                for (i = 0; i < psli->num_rings; i++) {
@@ -983,6 +984,9 @@ lpfc_hba_clean_txcmplq(struct lpfc_hba *phba)
                if (!pring)
                        continue;
                spin_lock_irq(&pring->ring_lock);
+               list_for_each_entry_safe(piocb, next_iocb,
+                                        &pring->txcmplq, list)
+                       piocb->iocb_flag &= ~LPFC_IO_ON_TXCMPLQ;
                list_splice_init(&pring->txcmplq, &completions);
                pring->txcmplq_cnt = 0;
                spin_unlock_irq(&pring->ring_lock);
index 8b2919a..d597e15 100644 (file)
@@ -3778,6 +3778,7 @@ lpfc_sli_flush_fcp_rings(struct lpfc_hba *phba)
        struct lpfc_sli *psli = &phba->sli;
        struct lpfc_sli_ring  *pring;
        uint32_t i;
+       struct lpfc_iocbq *piocb, *next_iocb;
 
        spin_lock_irq(&phba->hbalock);
        /* Indicate the I/O queues are flushed */
@@ -3792,6 +3793,9 @@ lpfc_sli_flush_fcp_rings(struct lpfc_hba *phba)
                        spin_lock_irq(&pring->ring_lock);
                        /* Retrieve everything on txq */
                        list_splice_init(&pring->txq, &txq);
+                       list_for_each_entry_safe(piocb, next_iocb,
+                                                &pring->txcmplq, list)
+                               piocb->iocb_flag &= ~LPFC_IO_ON_TXCMPLQ;
                        /* Retrieve everything on the txcmplq */
                        list_splice_init(&pring->txcmplq, &txcmplq);
                        pring->txq_cnt = 0;
@@ -3813,6 +3817,9 @@ lpfc_sli_flush_fcp_rings(struct lpfc_hba *phba)
                spin_lock_irq(&phba->hbalock);
                /* Retrieve everything on txq */
                list_splice_init(&pring->txq, &txq);
+               list_for_each_entry_safe(piocb, next_iocb,
+                                        &pring->txcmplq, list)
+                       piocb->iocb_flag &= ~LPFC_IO_ON_TXCMPLQ;
                /* Retrieve everything on the txcmplq */
                list_splice_init(&pring->txcmplq, &txcmplq);
                pring->txq_cnt = 0;
@@ -3844,6 +3851,7 @@ lpfc_sli_flush_nvme_rings(struct lpfc_hba *phba)
        LIST_HEAD(txcmplq);
        struct lpfc_sli_ring  *pring;
        uint32_t i;
+       struct lpfc_iocbq *piocb, *next_iocb;
 
        if (phba->sli_rev < LPFC_SLI_REV4)
                return;
@@ -3860,8 +3868,11 @@ lpfc_sli_flush_nvme_rings(struct lpfc_hba *phba)
        for (i = 0; i < phba->cfg_nvme_io_channel; i++) {
                pring = phba->sli4_hba.nvme_wq[i]->pring;
 
-               /* Retrieve everything on the txcmplq */
                spin_lock_irq(&pring->ring_lock);
+               list_for_each_entry_safe(piocb, next_iocb,
+                                        &pring->txcmplq, list)
+                       piocb->iocb_flag &= ~LPFC_IO_ON_TXCMPLQ;
+               /* Retrieve everything on the txcmplq */
                list_splice_init(&pring->txcmplq, &txcmplq);
                pring->txcmplq_cnt = 0;
                spin_unlock_irq(&pring->ring_lock);