summaryrefslogtreecommitdiff
path: root/drivers/ata
diff options
context:
space:
mode:
authorWei Fang <fangwei1@huawei.com>2016-06-07 09:53:56 +0300
committerSasha Levin <sasha.levin@oracle.com>2016-07-11 18:10:54 +0300
commitd6e98a6fc83d19ad85f52cad0111b047e51e61a9 (patch)
treea467e1bbf2cf4175fb23f303dae2e4e00ff7c968 /drivers/ata
parent6ff31a41c427154cb6592d4c1cc13bc6cbe52183 (diff)
downloadlinux-d6e98a6fc83d19ad85f52cad0111b047e51e61a9.tar.xz
scsi: fix race between simultaneous decrements of ->host_failed
[ Upstream commit 72d8c36ec364c82bf1bf0c64dfa1041cfaf139f7 ] sas_ata_strategy_handler() adds the works of the ata error handler to system_unbound_wq. This workqueue asynchronously runs work items, so the ata error handler will be performed concurrently on different CPUs. In this case, ->host_failed will be decreased simultaneously in scsi_eh_finish_cmd() on different CPUs, and become abnormal. It will lead to permanently inequality between ->host_failed and ->host_busy, and scsi error handler thread won't start running. IO errors after that won't be handled. Since all scmds must have been handled in the strategy handler, just remove the decrement in scsi_eh_finish_cmd() and zero ->host_busy after the strategy handler to fix this race. Fixes: 50824d6c5657 ("[SCSI] libsas: async ata-eh") Cc: stable@vger.kernel.org Signed-off-by: Wei Fang <fangwei1@huawei.com> Reviewed-by: James Bottomley <jejb@linux.vnet.ibm.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com> Signed-off-by: Sasha Levin <sasha.levin@oracle.com>
Diffstat (limited to 'drivers/ata')
-rw-r--r--drivers/ata/libata-eh.c2
1 files changed, 1 insertions, 1 deletions
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index 4ec95b76f6a1..0550c76f4e6c 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -605,7 +605,7 @@ void ata_scsi_error(struct Scsi_Host *host)
ata_scsi_port_error_handler(host, ap);
/* finish or retry handled scmd's and clean up */
- WARN_ON(host->host_failed || !list_empty(&eh_work_q));
+ WARN_ON(!list_empty(&eh_work_q));
DPRINTK("EXIT\n");
}