diff options
author | James Smart <jsmart2021@gmail.com> | 2018-09-10 10:30:46 -0700 |
---|---|---|
committer | Martin K. Petersen <martin.petersen@oracle.com> | 2018-09-11 20:37:33 -0400 |
commit | 523128e53b1e82a7eb422168eddd0c566973520d (patch) | |
tree | 919c6490bfb70ba9f8b91db59827c215a3691249 /drivers/scsi/lpfc/lpfc_init.c | |
parent | scsi: lpfc: Correct soft lockup when running mds diagnostics (diff) | |
download | linux-dev-523128e53b1e82a7eb422168eddd0c566973520d.tar.xz linux-dev-523128e53b1e82a7eb422168eddd0c566973520d.zip |
scsi: lpfc: Correct irq handling via locks when taking adapter offline
When taking the board offline while performing i/o, unsafe locking errors
occurred and irq level isn't properly managed.
In lpfc_sli_hba_down, spin_lock_irqsave(&phba->hbalock, flags) does not
disable softirqs raised from timer expiry. It is possible that a softirq is
raised from the lpfc_els_retry_delay routine and recursively requests the same
phba->hbalock spinlock causing deadlock.
Address the deadlocks by creating a new port_list lock. The softirq behavior
can then be managed a level deeper into the calling sequences.
Signed-off-by: Dick Kennedy <dick.kennedy@broadcom.com>
Signed-off-by: James Smart <james.smart@broadcom.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Diffstat (limited to '')
-rw-r--r-- | drivers/scsi/lpfc/lpfc_init.c | 19 |
1 files changed, 11 insertions, 8 deletions
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 90fb83f88179..bb2bff7b56b4 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -3988,9 +3988,9 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev) if (error) goto out_put_shost; - spin_lock_irq(&phba->hbalock); + spin_lock_irq(&phba->port_list_lock); list_add_tail(&vport->listentry, &phba->port_list); - spin_unlock_irq(&phba->hbalock); + spin_unlock_irq(&phba->port_list_lock); return vport; out_put_shost: @@ -4016,9 +4016,9 @@ destroy_port(struct lpfc_vport *vport) fc_remove_host(shost); scsi_remove_host(shost); - spin_lock_irq(&phba->hbalock); + spin_lock_irq(&phba->port_list_lock); list_del_init(&vport->listentry); - spin_unlock_irq(&phba->hbalock); + spin_unlock_irq(&phba->port_list_lock); lpfc_cleanup(vport); return; @@ -5621,7 +5621,10 @@ lpfc_setup_driver_resource_phase1(struct lpfc_hba *phba) /* Initialize ndlp management spinlock */ spin_lock_init(&phba->ndlp_lock); + /* Initialize port_list spinlock */ + spin_lock_init(&phba->port_list_lock); INIT_LIST_HEAD(&phba->port_list); + INIT_LIST_HEAD(&phba->work_list); init_waitqueue_head(&phba->wait_4_mlo_m_q); @@ -10985,9 +10988,9 @@ lpfc_pci_remove_one_s3(struct pci_dev *pdev) kfree(phba->vpi_ids); lpfc_stop_hba_timers(phba); - spin_lock_irq(&phba->hbalock); + spin_lock_irq(&phba->port_list_lock); list_del_init(&vport->listentry); - spin_unlock_irq(&phba->hbalock); + spin_unlock_irq(&phba->port_list_lock); lpfc_debugfs_terminate(vport); @@ -11797,9 +11800,9 @@ lpfc_pci_remove_one_s4(struct pci_dev *pdev) lpfc_sli4_hba_unset(phba); lpfc_stop_hba_timers(phba); - spin_lock_irq(&phba->hbalock); + spin_lock_irq(&phba->port_list_lock); list_del_init(&vport->listentry); - spin_unlock_irq(&phba->hbalock); + spin_unlock_irq(&phba->port_list_lock); /* Perform scsi free before driver resource_unset since scsi * buffers are released to their corresponding pools here. |