diff options
author | Christoph Hellwig <hch@lst.de> | 2015-09-27 15:01:50 -0400 |
---|---|---|
committer | Jens Axboe <axboe@fb.com> | 2015-10-01 04:10:55 -0400 |
commit | f4829a9b7a61e159367350008a608b062c4f6840 (patch) | |
tree | a2f488a95324e0c0b558273f48b18413ab2fa221 /block/blk-mq.c | |
parent | 60de074ba1e8f327db19bc33d8530131ac01695d (diff) |
blk-mq: fix racy updates of rq->errors
blk_mq_complete_request may be a no-op if the request has already
been completed by others means (e.g. a timeout or cancellation), but
currently drivers have to set rq->errors before calling
blk_mq_complete_request, which might leave us with the wrong error value.
Add an error parameter to blk_mq_complete_request so that we can
defer setting rq->errors until we known we won the race to complete the
request.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Sagi Grimberg <sagig@mellanox.com>
Signed-off-by: Jens Axboe <axboe@fb.com>
Diffstat (limited to 'block/blk-mq.c')
-rw-r--r-- | block/blk-mq.c | 12 |
1 files changed, 6 insertions, 6 deletions
diff --git a/block/blk-mq.c b/block/blk-mq.c index 31c0c6259c4c..2306330530e8 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c | |||
@@ -393,14 +393,16 @@ void __blk_mq_complete_request(struct request *rq) | |||
393 | * Ends all I/O on a request. It does not handle partial completions. | 393 | * Ends all I/O on a request. It does not handle partial completions. |
394 | * The actual completion happens out-of-order, through a IPI handler. | 394 | * The actual completion happens out-of-order, through a IPI handler. |
395 | **/ | 395 | **/ |
396 | void blk_mq_complete_request(struct request *rq) | 396 | void blk_mq_complete_request(struct request *rq, int error) |
397 | { | 397 | { |
398 | struct request_queue *q = rq->q; | 398 | struct request_queue *q = rq->q; |
399 | 399 | ||
400 | if (unlikely(blk_should_fake_timeout(q))) | 400 | if (unlikely(blk_should_fake_timeout(q))) |
401 | return; | 401 | return; |
402 | if (!blk_mark_rq_complete(rq)) | 402 | if (!blk_mark_rq_complete(rq)) { |
403 | rq->errors = error; | ||
403 | __blk_mq_complete_request(rq); | 404 | __blk_mq_complete_request(rq); |
405 | } | ||
404 | } | 406 | } |
405 | EXPORT_SYMBOL(blk_mq_complete_request); | 407 | EXPORT_SYMBOL(blk_mq_complete_request); |
406 | 408 | ||
@@ -616,10 +618,8 @@ static void blk_mq_check_expired(struct blk_mq_hw_ctx *hctx, | |||
616 | * If a request wasn't started before the queue was | 618 | * If a request wasn't started before the queue was |
617 | * marked dying, kill it here or it'll go unnoticed. | 619 | * marked dying, kill it here or it'll go unnoticed. |
618 | */ | 620 | */ |
619 | if (unlikely(blk_queue_dying(rq->q))) { | 621 | if (unlikely(blk_queue_dying(rq->q))) |
620 | rq->errors = -EIO; | 622 | blk_mq_complete_request(rq, -EIO); |
621 | blk_mq_complete_request(rq); | ||
622 | } | ||
623 | return; | 623 | return; |
624 | } | 624 | } |
625 | if (rq->cmd_flags & REQ_NO_TIMEOUT) | 625 | if (rq->cmd_flags & REQ_NO_TIMEOUT) |