* [PATCHv2 1/2] blk-mq: export setting request completion state
@ 2018-07-23 14:37 Keith Busch
2018-07-23 14:37 ` [PATCHv2 2/2] scsi: set timed out out mq requests to complete Keith Busch
` (2 more replies)
0 siblings, 3 replies; 11+ messages in thread
From: Keith Busch @ 2018-07-23 14:37 UTC (permalink / raw)
This is preparing for drivers that want to directly alter the state of
their requests. No functional change here.
Signed-off-by: Keith Busch <keith.busch at intel.com>
---
v1 -> v2:
Reversed the return value: 'true' for success instead of failure.
Document the caller's responsibilities after a successful state transtion.
block/blk-mq.c | 4 +---
include/linux/blk-mq.h | 14 ++++++++++++++
2 files changed, 15 insertions(+), 3 deletions(-)
diff --git a/block/blk-mq.c b/block/blk-mq.c
index 22326612a5d3..8f01cd7fd182 100644
--- a/block/blk-mq.c
+++ b/block/blk-mq.c
@@ -558,10 +558,8 @@ static void __blk_mq_complete_request(struct request *rq)
bool shared = false;
int cpu;
- if (cmpxchg(&rq->state, MQ_RQ_IN_FLIGHT, MQ_RQ_COMPLETE) !=
- MQ_RQ_IN_FLIGHT)
+ if (!blk_mq_mark_complete(rq))
return;
-
if (rq->internal_tag != -1)
blk_mq_sched_completed_request(rq);
diff --git a/include/linux/blk-mq.h b/include/linux/blk-mq.h
index 9b0fd11ce89a..4d41ed16314c 100644
--- a/include/linux/blk-mq.h
+++ b/include/linux/blk-mq.h
@@ -289,6 +289,20 @@ void blk_mq_update_nr_hw_queues(struct blk_mq_tag_set *set, int nr_hw_queues);
void blk_mq_quiesce_queue_nowait(struct request_queue *q);
+/**
+ * blk_mq_mark_complete() - Set request state to complete
+ * @rq: request to set to complete state
+ *
+ * Returns true if request state was successfully set to complete. If
+ * successful, the caller is responsibile for seeing this request is ended, as
+ * blk_mq_complete_request will not work again.
+ */
+static inline bool blk_mq_mark_complete(struct request *rq)
+{
+ return cmpxchg(&rq->state, MQ_RQ_IN_FLIGHT, MQ_RQ_COMPLETE) ==
+ MQ_RQ_IN_FLIGHT;
+}
+
/*
* Driver command data is immediately after the request. So subtract request
* size to get back to the original request, add request size to get the PDU.
--
2.14.4
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCHv2 2/2] scsi: set timed out out mq requests to complete
2018-07-23 14:37 [PATCHv2 1/2] blk-mq: export setting request completion state Keith Busch
@ 2018-07-23 14:37 ` Keith Busch
2018-07-24 7:56 ` Christoph Hellwig
` (2 more replies)
2018-07-24 7:56 ` [PATCHv2 1/2] blk-mq: export setting request completion state Christoph Hellwig
2018-07-24 20:42 ` Jens Axboe
2 siblings, 3 replies; 11+ messages in thread
From: Keith Busch @ 2018-07-23 14:37 UTC (permalink / raw)
The scsi block layer requires requests claimed by the error handling be
completed by the error handler. A previous commit allowed completions
to proceed for blk-mq, breaking that assumption.
This patch prevents completions that may race with the timeout handler
by marking the state to complete, restoring the previous behavior.
Fixes: 12f5b931 ("blk-mq: Remove generation seqeunce")
Signed-off-by: Keith Busch <keith.busch at intel.com>
---
v1 -> v2:
Document why this is necessary in code comments.
Update to API's changed return value
drivers/scsi/scsi_error.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index 8932ae81a15a..2715cdaa669c 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -296,6 +296,20 @@ enum blk_eh_timer_return scsi_times_out(struct request *req)
rtn = host->hostt->eh_timed_out(scmd);
if (rtn == BLK_EH_DONE) {
+ /*
+ * For blk-mq, we must set the request state to complete now
+ * before sending the request to the scsi error handler. This
+ * will prevent a use-after-free in the event the LLD manages
+ * to complete the request before the error handler finishes
+ * processing this timed out request.
+ *
+ * If the request was already completed, then the LLD beat the
+ * time out handler from transferring the request to the scsi
+ * error handler. In that case we can return immediately as no
+ * further action is required.
+ */
+ if (req->q->mq_ops && !blk_mq_mark_complete(req))
+ return rtn;
if (scsi_abort_command(scmd) != SUCCESS) {
set_host_byte(scmd, DID_TIME_OUT);
scsi_eh_scmd_add(scmd);
--
2.14.4
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCHv2 1/2] blk-mq: export setting request completion state
2018-07-23 14:37 [PATCHv2 1/2] blk-mq: export setting request completion state Keith Busch
2018-07-23 14:37 ` [PATCHv2 2/2] scsi: set timed out out mq requests to complete Keith Busch
@ 2018-07-24 7:56 ` Christoph Hellwig
2018-07-24 20:42 ` Jens Axboe
2 siblings, 0 replies; 11+ messages in thread
From: Christoph Hellwig @ 2018-07-24 7:56 UTC (permalink / raw)
Looks good,
Reviewed-by: Christoph Hellwig <hch at lst.de>
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCHv2 2/2] scsi: set timed out out mq requests to complete
2018-07-23 14:37 ` [PATCHv2 2/2] scsi: set timed out out mq requests to complete Keith Busch
@ 2018-07-24 7:56 ` Christoph Hellwig
2018-07-24 22:46 ` Bart Van Assche
2018-07-25 15:52 ` Bart Van Assche
2 siblings, 0 replies; 11+ messages in thread
From: Christoph Hellwig @ 2018-07-24 7:56 UTC (permalink / raw)
On Mon, Jul 23, 2018@08:37:51AM -0600, Keith Busch wrote:
> The scsi block layer requires requests claimed by the error handling be
> completed by the error handler. A previous commit allowed completions
> to proceed for blk-mq, breaking that assumption.
>
> This patch prevents completions that may race with the timeout handler
> by marking the state to complete, restoring the previous behavior.
>
> Fixes: 12f5b931 ("blk-mq: Remove generation seqeunce")
> Signed-off-by: Keith Busch <keith.busch at intel.com>
Looks good enough (reluctantly) for this merge window:
Reviewed-by: Christoph Hellwig <hch at lst.de>
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCHv2 1/2] blk-mq: export setting request completion state
2018-07-23 14:37 [PATCHv2 1/2] blk-mq: export setting request completion state Keith Busch
2018-07-23 14:37 ` [PATCHv2 2/2] scsi: set timed out out mq requests to complete Keith Busch
2018-07-24 7:56 ` [PATCHv2 1/2] blk-mq: export setting request completion state Christoph Hellwig
@ 2018-07-24 20:42 ` Jens Axboe
2 siblings, 0 replies; 11+ messages in thread
From: Jens Axboe @ 2018-07-24 20:42 UTC (permalink / raw)
On 7/23/18 7:37 AM, Keith Busch wrote:
> This is preparing for drivers that want to directly alter the state of
> their requests. No functional change here.
Added this (and 2/2) for 4.18...
--
Jens Axboe
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCHv2 2/2] scsi: set timed out out mq requests to complete
2018-07-23 14:37 ` [PATCHv2 2/2] scsi: set timed out out mq requests to complete Keith Busch
2018-07-24 7:56 ` Christoph Hellwig
@ 2018-07-24 22:46 ` Bart Van Assche
2018-07-25 1:15 ` Keith Busch
2018-07-25 15:52 ` Bart Van Assche
2 siblings, 1 reply; 11+ messages in thread
From: Bart Van Assche @ 2018-07-24 22:46 UTC (permalink / raw)
On 07/23/18 07:37, Keith Busch wrote:
> diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
> index 8932ae81a15a..2715cdaa669c 100644
> --- a/drivers/scsi/scsi_error.c
> +++ b/drivers/scsi/scsi_error.c
> @@ -296,6 +296,20 @@ enum blk_eh_timer_return scsi_times_out(struct request *req)
> rtn = host->hostt->eh_timed_out(scmd);
>
> if (rtn == BLK_EH_DONE) {
> + /*
> + * For blk-mq, we must set the request state to complete now
> + * before sending the request to the scsi error handler. This
> + * will prevent a use-after-free in the event the LLD manages
> + * to complete the request before the error handler finishes
> + * processing this timed out request.
> + *
> + * If the request was already completed, then the LLD beat the
> + * time out handler from transferring the request to the scsi
> + * error handler. In that case we can return immediately as no
> + * further action is required.
> + */
> + if (req->q->mq_ops && !blk_mq_mark_complete(req))
> + return rtn;
> if (scsi_abort_command(scmd) != SUCCESS) {
> set_host_byte(scmd, DID_TIME_OUT);
> scsi_eh_scmd_add(scmd);
This change looks incomplete to me. I think the following scenario is
not handled properly by the above patch:
- host->hostt->eh_timed_out() gets called.
- The request "req" completes from another context while
host->hostt->eh_timed_out() is in progress.
- host->hostt->eh_timed_out() calls scsi_finish_command().
I think that scenario will lead to a double completion.
Bart.
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCHv2 2/2] scsi: set timed out out mq requests to complete
2018-07-24 22:46 ` Bart Van Assche
@ 2018-07-25 1:15 ` Keith Busch
2018-07-25 1:56 ` Douglas Gilbert
0 siblings, 1 reply; 11+ messages in thread
From: Keith Busch @ 2018-07-25 1:15 UTC (permalink / raw)
On Tue, Jul 24, 2018@03:46:17PM -0700, Bart Van Assche wrote:
> On 07/23/18 07:37, Keith Busch wrote:
> > + if (req->q->mq_ops && !blk_mq_mark_complete(req))
> > + return rtn;
> > if (scsi_abort_command(scmd) != SUCCESS) {
> > set_host_byte(scmd, DID_TIME_OUT);
> > scsi_eh_scmd_add(scmd);
>
> This change looks incomplete to me. I think the following scenario is not
> handled properly by the above patch:
> - host->hostt->eh_timed_out() gets called.
> - The request "req" completes from another context while
> host->hostt->eh_timed_out() is in progress.
> - host->hostt->eh_timed_out() calls scsi_finish_command().
>
> I think that scenario will lead to a double completion.
A bit of a moot point, isn't it? Not a single scsi lld directly calls
scsi_finish_command() from anywhere, much less through eh_timed_out().
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCHv2 2/2] scsi: set timed out out mq requests to complete
2018-07-25 1:15 ` Keith Busch
@ 2018-07-25 1:56 ` Douglas Gilbert
2018-07-25 2:48 ` Keith Busch
0 siblings, 1 reply; 11+ messages in thread
From: Douglas Gilbert @ 2018-07-25 1:56 UTC (permalink / raw)
On 2018-07-24 09:15 PM, Keith Busch wrote:
> On Tue, Jul 24, 2018@03:46:17PM -0700, Bart Van Assche wrote:
>> On 07/23/18 07:37, Keith Busch wrote:
>>> + if (req->q->mq_ops && !blk_mq_mark_complete(req))
>>> + return rtn;
>>> if (scsi_abort_command(scmd) != SUCCESS) {
>>> set_host_byte(scmd, DID_TIME_OUT);
>>> scsi_eh_scmd_add(scmd);
>>
>> This change looks incomplete to me. I think the following scenario is not
>> handled properly by the above patch:
>> - host->hostt->eh_timed_out() gets called.
>> - The request "req" completes from another context while
>> host->hostt->eh_timed_out() is in progress.
>> - host->hostt->eh_timed_out() calls scsi_finish_command().
>>
>> I think that scenario will lead to a double completion.
>
> A bit of a moot point, isn't it? Not a single scsi lld directly calls
> scsi_finish_command() from anywhere, much less through eh_timed_out().
" * scsi_finish_command - cleanup and pass command back to upper layer"
That is from the comment block above the definition of scsi_finish_command().
To me that means the mid-level has already got the response from the LLD
(directly via a queuecommand() return, or asynchronously via the scsi_done()
callback) and this function will call the "upper layer" which will be
the one of the sd, sr, st, sg, ses, etc drivers that originated the command
for that UL-driver's completion.
In USB Type C speak, the SCSI mid level has two interfaces, one downward
facing (toward LLDs) and one upward facing (toward the drivers listed above).
No LLD should be calling scsi_finish_command() IMO.
Doug Gilbert
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCHv2 2/2] scsi: set timed out out mq requests to complete
2018-07-25 1:56 ` Douglas Gilbert
@ 2018-07-25 2:48 ` Keith Busch
0 siblings, 0 replies; 11+ messages in thread
From: Keith Busch @ 2018-07-25 2:48 UTC (permalink / raw)
On Tue, Jul 24, 2018@09:56:35PM -0400, dgilbert@interlog.com wrote:
> No LLD should be calling scsi_finish_command() IMO.
Agreed. I don't even think scsi's error handler should directly call it
either, but detangling that may take some time, if ever.
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCHv2 2/2] scsi: set timed out out mq requests to complete
2018-07-23 14:37 ` [PATCHv2 2/2] scsi: set timed out out mq requests to complete Keith Busch
2018-07-24 7:56 ` Christoph Hellwig
2018-07-24 22:46 ` Bart Van Assche
@ 2018-07-25 15:52 ` Bart Van Assche
2018-07-25 16:48 ` Keith Busch
2 siblings, 1 reply; 11+ messages in thread
From: Bart Van Assche @ 2018-07-25 15:52 UTC (permalink / raw)
On Mon, 2018-07-23@08:37 -0600, Keith Busch wrote:
> diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
> index 8932ae81a15a..2715cdaa669c 100644
> --- a/drivers/scsi/scsi_error.c
> +++ b/drivers/scsi/scsi_error.c
> @@ -296,6 +296,20 @@ enum blk_eh_timer_return scsi_times_out(struct request *req)
> rtn = host->hostt->eh_timed_out(scmd);
>
> if (rtn == BLK_EH_DONE) {
> + /*
> + * For blk-mq, we must set the request state to complete now
> + * before sending the request to the scsi error handler. This
> + * will prevent a use-after-free in the event the LLD manages
> + * to complete the request before the error handler finishes
> + * processing this timed out request.
> + *
> + * If the request was already completed, then the LLD beat the
> + * time out handler from transferring the request to the scsi
> + * error handler. In that case we can return immediately as no
> + * further action is required.
> + */
> + if (req->q->mq_ops && !blk_mq_mark_complete(req))
> + return rtn;
> if (scsi_abort_command(scmd) != SUCCESS) {
> set_host_byte(scmd, DID_TIME_OUT);
> scsi_eh_scmd_add(scmd);
Hello Keith,
What will happen if a completion occurs after scsi_times_out() has started and
before or during the host->hostt->eh_timed_out()? Can that cause a use-after-free
in .eh_timed_out()? Can that cause .eh_timed_out() to return BLK_EH_RESET_TIMER
when it should return BLK_EH_DONE? Can that cause blk_mq_rq_timed_out() to call
blk_add_timer() when that function shouldn't be called?
Thanks,
Bart.
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCHv2 2/2] scsi: set timed out out mq requests to complete
2018-07-25 15:52 ` Bart Van Assche
@ 2018-07-25 16:48 ` Keith Busch
0 siblings, 0 replies; 11+ messages in thread
From: Keith Busch @ 2018-07-25 16:48 UTC (permalink / raw)
On Wed, Jul 25, 2018@03:52:17PM +0000, Bart Van Assche wrote:
> On Mon, 2018-07-23@08:37 -0600, Keith Busch wrote:
> > diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
> > index 8932ae81a15a..2715cdaa669c 100644
> > --- a/drivers/scsi/scsi_error.c
> > +++ b/drivers/scsi/scsi_error.c
> > @@ -296,6 +296,20 @@ enum blk_eh_timer_return scsi_times_out(struct request *req)
> > rtn = host->hostt->eh_timed_out(scmd);
> >
> > if (rtn == BLK_EH_DONE) {
> > + /*
> > + * For blk-mq, we must set the request state to complete now
> > + * before sending the request to the scsi error handler. This
> > + * will prevent a use-after-free in the event the LLD manages
> > + * to complete the request before the error handler finishes
> > + * processing this timed out request.
> > + *
> > + * If the request was already completed, then the LLD beat the
> > + * time out handler from transferring the request to the scsi
> > + * error handler. In that case we can return immediately as no
> > + * further action is required.
> > + */
> > + if (req->q->mq_ops && !blk_mq_mark_complete(req))
> > + return rtn;
> > if (scsi_abort_command(scmd) != SUCCESS) {
> > set_host_byte(scmd, DID_TIME_OUT);
> > scsi_eh_scmd_add(scmd);
>
> Hello Keith,
>
> What will happen if a completion occurs after scsi_times_out() has started and
> before or during the host->hostt->eh_timed_out()? Can that cause a use-after-free
> in .eh_timed_out()? Can that cause .eh_timed_out() to return BLK_EH_RESET_TIMER
> when it should return BLK_EH_DONE? Can that cause blk_mq_rq_timed_out() to call
> blk_add_timer() when that function shouldn't be called?
That's what the request's refcount protects. The whole point was that
driver returning RESET_TIMER doesn't lose the completion. In the worst
case scenario, the blk-mq timeout work spends some CPU cycles re-arming
a timer that it didn't need to.
^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2018-07-25 16:48 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2018-07-23 14:37 [PATCHv2 1/2] blk-mq: export setting request completion state Keith Busch
2018-07-23 14:37 ` [PATCHv2 2/2] scsi: set timed out out mq requests to complete Keith Busch
2018-07-24 7:56 ` Christoph Hellwig
2018-07-24 22:46 ` Bart Van Assche
2018-07-25 1:15 ` Keith Busch
2018-07-25 1:56 ` Douglas Gilbert
2018-07-25 2:48 ` Keith Busch
2018-07-25 15:52 ` Bart Van Assche
2018-07-25 16:48 ` Keith Busch
2018-07-24 7:56 ` [PATCHv2 1/2] blk-mq: export setting request completion state Christoph Hellwig
2018-07-24 20:42 ` Jens Axboe
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).