diff options
author | Keith Busch <keith.busch@intel.com> | 2018-11-26 11:54:29 -0500 |
---|---|---|
committer | Jens Axboe <axboe@kernel.dk> | 2018-11-26 12:34:26 -0500 |
commit | f1342709d18af97b0e71449d5696b8873d1a456c (patch) | |
tree | bb820e311b26912b1eef37a53573d52fea6dfeb1 | |
parent | 16c15eb16a793f2d81ae52f41f43fb6831b34212 (diff) |
scsi: Do not rely on blk-mq for double completions
The scsi timeout error handling had been directly updating the block
layer's request state to prevent a error handling and a natural completion
from completing the same request twice. Fix this layering violation
by having scsi control the fate of its commands with scsi owned flags
rather than use blk-mq's.
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Keith Busch <keith.busch@intel.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
-rw-r--r-- | drivers/scsi/scsi_error.c | 22 | ||||
-rw-r--r-- | drivers/scsi/scsi_lib.c | 13 | ||||
-rw-r--r-- | include/scsi/scsi_cmnd.h | 4 |
3 files changed, 27 insertions, 12 deletions
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index dd338a8cd275..16eef068e9e9 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c | |||
@@ -297,19 +297,19 @@ enum blk_eh_timer_return scsi_times_out(struct request *req) | |||
297 | 297 | ||
298 | if (rtn == BLK_EH_DONE) { | 298 | if (rtn == BLK_EH_DONE) { |
299 | /* | 299 | /* |
300 | * For blk-mq, we must set the request state to complete now | 300 | * Set the command to complete first in order to prevent a real |
301 | * before sending the request to the scsi error handler. This | 301 | * completion from releasing the command while error handling |
302 | * will prevent a use-after-free in the event the LLD manages | 302 | * is using it. If the command was already completed, then the |
303 | * to complete the request before the error handler finishes | 303 | * lower level driver beat the timeout handler, and it is safe |
304 | * processing this timed out request. | 304 | * to return without escalating error recovery. |
305 | * | 305 | * |
306 | * If the request was already completed, then the LLD beat the | 306 | * If timeout handling lost the race to a real completion, the |
307 | * time out handler from transferring the request to the scsi | 307 | * block layer may ignore that due to a fake timeout injection, |
308 | * error handler. In that case we can return immediately as no | 308 | * so return RESET_TIMER to allow error handling another shot |
309 | * further action is required. | 309 | * at this command. |
310 | */ | 310 | */ |
311 | if (!blk_mq_mark_complete(req)) | 311 | if (test_and_set_bit(SCMD_STATE_COMPLETE, &scmd->state)) |
312 | return rtn; | 312 | return BLK_EH_RESET_TIMER; |
313 | if (scsi_abort_command(scmd) != SUCCESS) { | 313 | if (scsi_abort_command(scmd) != SUCCESS) { |
314 | set_host_byte(scmd, DID_TIME_OUT); | 314 | set_host_byte(scmd, DID_TIME_OUT); |
315 | scsi_eh_scmd_add(scmd); | 315 | scsi_eh_scmd_add(scmd); |
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 0df15cb738d2..0dbf25512778 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c | |||
@@ -1642,8 +1642,18 @@ static blk_status_t scsi_mq_prep_fn(struct request *req) | |||
1642 | 1642 | ||
1643 | static void scsi_mq_done(struct scsi_cmnd *cmd) | 1643 | static void scsi_mq_done(struct scsi_cmnd *cmd) |
1644 | { | 1644 | { |
1645 | if (unlikely(test_and_set_bit(SCMD_STATE_COMPLETE, &cmd->state))) | ||
1646 | return; | ||
1645 | trace_scsi_dispatch_cmd_done(cmd); | 1647 | trace_scsi_dispatch_cmd_done(cmd); |
1646 | blk_mq_complete_request(cmd->request); | 1648 | |
1649 | /* | ||
1650 | * If the block layer didn't complete the request due to a timeout | ||
1651 | * injection, scsi must clear its internal completed state so that the | ||
1652 | * timeout handler will see it needs to escalate its own error | ||
1653 | * recovery. | ||
1654 | */ | ||
1655 | if (unlikely(!blk_mq_complete_request(cmd->request))) | ||
1656 | clear_bit(SCMD_STATE_COMPLETE, &cmd->state); | ||
1647 | } | 1657 | } |
1648 | 1658 | ||
1649 | static void scsi_mq_put_budget(struct blk_mq_hw_ctx *hctx) | 1659 | static void scsi_mq_put_budget(struct blk_mq_hw_ctx *hctx) |
@@ -1702,6 +1712,7 @@ static blk_status_t scsi_queue_rq(struct blk_mq_hw_ctx *hctx, | |||
1702 | if (!scsi_host_queue_ready(q, shost, sdev)) | 1712 | if (!scsi_host_queue_ready(q, shost, sdev)) |
1703 | goto out_dec_target_busy; | 1713 | goto out_dec_target_busy; |
1704 | 1714 | ||
1715 | clear_bit(SCMD_STATE_COMPLETE, &cmd->state); | ||
1705 | if (!(req->rq_flags & RQF_DONTPREP)) { | 1716 | if (!(req->rq_flags & RQF_DONTPREP)) { |
1706 | ret = scsi_mq_prep_fn(req); | 1717 | ret = scsi_mq_prep_fn(req); |
1707 | if (ret != BLK_STS_OK) | 1718 | if (ret != BLK_STS_OK) |
diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h index d6fd2aba0380..3de905e205ce 100644 --- a/include/scsi/scsi_cmnd.h +++ b/include/scsi/scsi_cmnd.h | |||
@@ -61,6 +61,9 @@ struct scsi_pointer { | |||
61 | /* flags preserved across unprep / reprep */ | 61 | /* flags preserved across unprep / reprep */ |
62 | #define SCMD_PRESERVED_FLAGS (SCMD_UNCHECKED_ISA_DMA | SCMD_INITIALIZED) | 62 | #define SCMD_PRESERVED_FLAGS (SCMD_UNCHECKED_ISA_DMA | SCMD_INITIALIZED) |
63 | 63 | ||
64 | /* for scmd->state */ | ||
65 | #define SCMD_STATE_COMPLETE (1 << 0) | ||
66 | |||
64 | struct scsi_cmnd { | 67 | struct scsi_cmnd { |
65 | struct scsi_request req; | 68 | struct scsi_request req; |
66 | struct scsi_device *device; | 69 | struct scsi_device *device; |
@@ -145,6 +148,7 @@ struct scsi_cmnd { | |||
145 | 148 | ||
146 | int result; /* Status code from lower level driver */ | 149 | int result; /* Status code from lower level driver */ |
147 | int flags; /* Command flags */ | 150 | int flags; /* Command flags */ |
151 | unsigned long state; /* Command completion state */ | ||
148 | 152 | ||
149 | unsigned char tag; /* SCSI-II queued command tag */ | 153 | unsigned char tag; /* SCSI-II queued command tag */ |
150 | }; | 154 | }; |