diff options
author | Wei Fang <fangwei1@huawei.com> | 2016-06-07 14:53:56 +0800 |
---|---|---|
committer | Jiri Slaby <jslaby@suse.cz> | 2016-08-19 09:50:51 +0200 |
commit | ac00a333f15796522e7dda343d9447459dc46b94 (patch) | |
tree | 92ecf0a12c5e804c2f5d33e45529d62dd483f48a /drivers/scsi | |
parent | ce3b334f59be6943b3754d395802187bf317ac31 (diff) | |
download | lwn-ac00a333f15796522e7dda343d9447459dc46b94.tar.gz lwn-ac00a333f15796522e7dda343d9447459dc46b94.zip |
scsi: fix race between simultaneous decrements of ->host_failed
commit 72d8c36ec364c82bf1bf0c64dfa1041cfaf139f7 upstream.
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")
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: Jiri Slaby <jslaby@suse.cz>
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/scsi_error.c | 4 |
1 files changed, 3 insertions, 1 deletions
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index ff2689d01209..bb40359ba620 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -960,7 +960,6 @@ static int scsi_request_sense(struct scsi_cmnd *scmd) */ void scsi_eh_finish_cmd(struct scsi_cmnd *scmd, struct list_head *done_q) { - scmd->device->host->host_failed--; scmd->eh_eflags = 0; list_move_tail(&scmd->eh_entry, done_q); } @@ -1949,6 +1948,9 @@ int scsi_error_handler(void *data) else scsi_unjam_host(shost); + /* All scmds have been handled */ + shost->host_failed = 0; + /* * Note - if the above fails completely, the action is to take * individual devices offline and flush the queue of any |