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>
Dieser Commit ist enthalten in:

committet von
Martin K. Petersen

Ursprung
0ef01a2d95
Commit
523128e53b
@@ -207,7 +207,7 @@ lpfc_unique_wwpn(struct lpfc_hba *phba, struct lpfc_vport *new_vport)
|
||||
struct lpfc_vport *vport;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&phba->hbalock, flags);
|
||||
spin_lock_irqsave(&phba->port_list_lock, flags);
|
||||
list_for_each_entry(vport, &phba->port_list, listentry) {
|
||||
if (vport == new_vport)
|
||||
continue;
|
||||
@@ -215,11 +215,11 @@ lpfc_unique_wwpn(struct lpfc_hba *phba, struct lpfc_vport *new_vport)
|
||||
if (memcmp(&vport->fc_sparam.portName,
|
||||
&new_vport->fc_sparam.portName,
|
||||
sizeof(struct lpfc_name)) == 0) {
|
||||
spin_unlock_irqrestore(&phba->hbalock, flags);
|
||||
spin_unlock_irqrestore(&phba->port_list_lock, flags);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&phba->hbalock, flags);
|
||||
spin_unlock_irqrestore(&phba->port_list_lock, flags);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -825,9 +825,9 @@ skip_logo:
|
||||
|
||||
lpfc_free_vpi(phba, vport->vpi);
|
||||
vport->work_port_events = 0;
|
||||
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_printf_vlog(vport, KERN_ERR, LOG_VPORT,
|
||||
"1828 Vport Deleted.\n");
|
||||
scsi_host_put(shost);
|
||||
@@ -844,7 +844,7 @@ lpfc_create_vport_work_array(struct lpfc_hba *phba)
|
||||
GFP_KERNEL);
|
||||
if (vports == NULL)
|
||||
return NULL;
|
||||
spin_lock_irq(&phba->hbalock);
|
||||
spin_lock_irq(&phba->port_list_lock);
|
||||
list_for_each_entry(port_iterator, &phba->port_list, listentry) {
|
||||
if (port_iterator->load_flag & FC_UNLOADING)
|
||||
continue;
|
||||
@@ -856,7 +856,7 @@ lpfc_create_vport_work_array(struct lpfc_hba *phba)
|
||||
}
|
||||
vports[index++] = port_iterator;
|
||||
}
|
||||
spin_unlock_irq(&phba->hbalock);
|
||||
spin_unlock_irq(&phba->port_list_lock);
|
||||
return vports;
|
||||
}
|
||||
|
||||
|
In neuem Issue referenzieren
Einen Benutzer sperren