提交 02e500a0 编写于 作者: J Jason Yan 提交者: Xie XiuQi

scsi: ata: Fix a race condition between scsi error handler and ahci interrupt

euler inclusion
category: bugfix
bugzilla: NA
CVE: NA

---------------------------

   interrupt                                          scsi_eh

ahci_error_intr
  =>ata_port_freeze
    =>__ata_port_freeze
      =>ahci_freeze (turn IRQ off)
    =>ata_port_abort
      =>ata_port_schedule_eh
        =>shost->host_eh_scheduled++;
	host_eh_scheduled = 1
                                                 scsi_error_handler
						   =>ata_scsi_error
						     =>ata_scsi_port_error_handler
						       =>ahci_error_handler
						       . =>sata_pmp_error_handler
						       .   =>ata_eh_thaw_port
						       .     =>ahci_thaw (turn IRQ on)
ahci_error_intr                                        .
  =>ata_port_freeze                                    .
    =>__ata_port_freeze                                .
      =>ahci_freeze (turn IRQ off)                     .
    =>ata_port_abort                                   .
      =>ata_port_schedule_eh                           .
        =>shost->host_eh_scheduled++;                  .
	host_eh_scheduled = 2                          .
						       =>ata_std_end_eh
						         =>host->host_eh_scheduled = 0;

host_eh_scheduled is 0 and scsi eh thread will not be scheduled again,
and the ata port remain freeze and will never be enabled.
Reported-by: Nluojian <luojian5@huawei.com>
Signed-off-by: NJason Yan <yanaijie@huawei.com>
Reviewed-by: Nzhengbin <zhengbin13@huawei.com>
Signed-off-by: NYang Yingliang <yangyingliang@huawei.com>
上级 1269a2ec
......@@ -974,7 +974,7 @@ void ata_std_end_eh(struct ata_port *ap)
{
struct Scsi_Host *host = ap->scsi_host;
host->host_eh_scheduled = 0;
atomic_dec(&host->host_eh_scheduled);
}
EXPORT_SYMBOL(ata_std_end_eh);
......
......@@ -492,7 +492,7 @@ int sas_eh_abort_handler(struct scsi_cmnd *cmd)
spin_lock_irqsave(host->host_lock, flags);
/* We cannot do async aborts for SATA devices */
if (dev_is_sata(dev) && !host->host_eh_scheduled) {
if (dev_is_sata(dev) && !atomic_read(&host->host_eh_scheduled)) {
spin_unlock_irqrestore(host->host_lock, flags);
return FAILED;
}
......@@ -792,7 +792,7 @@ void sas_scsi_recover_host(struct Scsi_Host *shost)
/* check if any new eh work was scheduled during the last run */
spin_lock_irq(&ha->lock);
if (ha->eh_active == 0) {
shost->host_eh_scheduled = 0;
atomic_set(&shost->host_eh_scheduled, 0);
retry = false;
}
spin_unlock_irq(&ha->lock);
......
......@@ -88,7 +88,7 @@ void scsi_schedule_eh(struct Scsi_Host *shost)
if (scsi_host_set_state(shost, SHOST_RECOVERY) == 0 ||
scsi_host_set_state(shost, SHOST_CANCEL_RECOVERY) == 0) {
shost->host_eh_scheduled++;
atomic_inc(&shost->host_eh_scheduled);
scsi_eh_wakeup(shost);
}
......@@ -2029,7 +2029,7 @@ static void scsi_restart_operations(struct Scsi_Host *shost)
* pending commands complete.
*/
spin_lock_irqsave(shost->host_lock, flags);
if (shost->host_eh_scheduled)
if (atomic_read(&shost->host_eh_scheduled))
if (scsi_host_set_state(shost, SHOST_RECOVERY))
WARN_ON(scsi_host_set_state(shost, SHOST_CANCEL_RECOVERY));
spin_unlock_irqrestore(shost->host_lock, flags);
......@@ -2165,7 +2165,8 @@ int scsi_error_handler(void *data)
if (kthread_should_stop())
break;
if ((shost->host_failed == 0 && shost->host_eh_scheduled == 0) ||
if ((shost->host_failed == 0 &&
atomic_read(&shost->host_eh_scheduled) == 0) ||
shost->host_failed != scsi_host_busy(shost)) {
SCSI_LOG_ERROR_RECOVERY(1,
shost_printk(KERN_INFO, shost,
......@@ -2179,7 +2180,8 @@ int scsi_error_handler(void *data)
SCSI_LOG_ERROR_RECOVERY(1,
shost_printk(KERN_INFO, shost,
"scsi_eh_%d: waking up %d/%d/%d\n",
shost->host_no, shost->host_eh_scheduled,
shost->host_no,
atomic_read(&shost->host_eh_scheduled),
shost->host_failed,
scsi_host_busy(shost)));
......
......@@ -348,7 +348,8 @@ static void scsi_dec_host_busy(struct Scsi_Host *shost)
atomic_dec(&shost->host_busy);
if (unlikely(scsi_host_in_recovery(shost))) {
spin_lock_irqsave(shost->host_lock, flags);
if (shost->host_failed || shost->host_eh_scheduled)
if (shost->host_failed ||
atomic_read(&shost->host_eh_scheduled))
scsi_eh_wakeup(shost);
spin_unlock_irqrestore(shost->host_lock, flags);
}
......
......@@ -561,7 +561,7 @@ struct Scsi_Host {
unsigned int host_failed; /* commands that failed.
protected by host_lock */
unsigned int host_eh_scheduled; /* EH scheduled without command */
atomic_t host_eh_scheduled; /* EH scheduled without command */
unsigned int host_no; /* Used for IOCTL_GET_IDLUN, /proc/scsi et al. */
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册