All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] blk-mq: don't queue more if we get a busy return
@ 2018-06-28 15:46 Jens Axboe
  2018-06-28 17:37 ` Omar Sandoval
  2018-06-29  1:59 ` Ming Lei
  0 siblings, 2 replies; 5+ messages in thread
From: Jens Axboe @ 2018-06-28 15:46 UTC (permalink / raw)
  To: linux-block

Some devices have different queue limits depending on the type of IO. A
classic case is SATA NCQ, where some commands can queue, but others
cannot. If we have NCQ commands inflight and encounter a non-queueable
command, the driver returns busy. Currently we attempt to dispatch more
from the scheduler, if we were able to queue some commands. But for the
case where we ended up stopping due to BUSY, we should not attempt to
retrieve more from the scheduler. If we do, we can get into a situation
where we attempt to queue a non-queueable command, get BUSY, then
successfully retrieve more commands from that scheduler and queue those.
This can repeat forever, starving the non-queuable command indefinitely.

Fix this by NOT attempting to pull more commands from the scheduler, if
we get a BUSY return. This should also be more optimal in terms of
letting requests stay in the scheduler for as long as possible, if we
get a BUSY due to the regular out-of-tags condition.

Signed-off-by: Jens Axboe <axboe@kernel.dk>

diff --git a/block/blk-mq.c b/block/blk-mq.c
index b6888ff556cf..d394cdd8d8c6 100644
--- a/block/blk-mq.c
+++ b/block/blk-mq.c
@@ -1075,6 +1075,9 @@ static bool blk_mq_mark_tag_wait(struct blk_mq_hw_ctx **hctx,
 
 #define BLK_MQ_RESOURCE_DELAY	3		/* ms units */
 
+/*
+ * Returns true if we did some work AND can potentially do more.
+ */
 bool blk_mq_dispatch_rq_list(struct request_queue *q, struct list_head *list,
 			     bool got_budget)
 {
@@ -1205,8 +1208,17 @@ bool blk_mq_dispatch_rq_list(struct request_queue *q, struct list_head *list,
 			blk_mq_run_hw_queue(hctx, true);
 		else if (needs_restart && (ret == BLK_STS_RESOURCE))
 			blk_mq_delay_run_hw_queue(hctx, BLK_MQ_RESOURCE_DELAY);
+
+		return false;
 	}
 
+	/*
+	 * If the host/device is unable to accept more work, inform the
+	 * caller of that.
+	 */
+	if (ret == BLK_STS_RESOURCE || ret == BLK_STS_DEV_RESOURCE)
+		return false;
+
 	return (queued + errors) != 0;
 }
 
-- 
Jens Axboe
 

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH] blk-mq: don't queue more if we get a busy return
  2018-06-28 15:46 [PATCH] blk-mq: don't queue more if we get a busy return Jens Axboe
@ 2018-06-28 17:37 ` Omar Sandoval
  2018-06-29  1:59 ` Ming Lei
  1 sibling, 0 replies; 5+ messages in thread
From: Omar Sandoval @ 2018-06-28 17:37 UTC (permalink / raw)
  To: Jens Axboe; +Cc: linux-block

On Thu, Jun 28, 2018 at 09:46:50AM -0600, Jens Axboe wrote:
> Some devices have different queue limits depending on the type of IO. A
> classic case is SATA NCQ, where some commands can queue, but others
> cannot. If we have NCQ commands inflight and encounter a non-queueable
> command, the driver returns busy. Currently we attempt to dispatch more
> from the scheduler, if we were able to queue some commands. But for the
> case where we ended up stopping due to BUSY, we should not attempt to
> retrieve more from the scheduler. If we do, we can get into a situation
> where we attempt to queue a non-queueable command, get BUSY, then
> successfully retrieve more commands from that scheduler and queue those.
> This can repeat forever, starving the non-queuable command indefinitely.
> 
> Fix this by NOT attempting to pull more commands from the scheduler, if
> we get a BUSY return. This should also be more optimal in terms of
> letting requests stay in the scheduler for as long as possible, if we
> get a BUSY due to the regular out-of-tags condition.

Reviewed-by: Omar Sandoval <osandov@fb.com>
> Signed-off-by: Jens Axboe <axboe@kernel.dk>
> 
> diff --git a/block/blk-mq.c b/block/blk-mq.c
> index b6888ff556cf..d394cdd8d8c6 100644
> --- a/block/blk-mq.c
> +++ b/block/blk-mq.c
> @@ -1075,6 +1075,9 @@ static bool blk_mq_mark_tag_wait(struct blk_mq_hw_ctx **hctx,
>  
>  #define BLK_MQ_RESOURCE_DELAY	3		/* ms units */
>  
> +/*
> + * Returns true if we did some work AND can potentially do more.
> + */
>  bool blk_mq_dispatch_rq_list(struct request_queue *q, struct list_head *list,
>  			     bool got_budget)
>  {
> @@ -1205,8 +1208,17 @@ bool blk_mq_dispatch_rq_list(struct request_queue *q, struct list_head *list,
>  			blk_mq_run_hw_queue(hctx, true);
>  		else if (needs_restart && (ret == BLK_STS_RESOURCE))
>  			blk_mq_delay_run_hw_queue(hctx, BLK_MQ_RESOURCE_DELAY);
> +
> +		return false;
>  	}
>  
> +	/*
> +	 * If the host/device is unable to accept more work, inform the
> +	 * caller of that.
> +	 */
> +	if (ret == BLK_STS_RESOURCE || ret == BLK_STS_DEV_RESOURCE)
> +		return false;
> +
>  	return (queued + errors) != 0;
>  }
>  
> -- 
> Jens Axboe
>  

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] blk-mq: don't queue more if we get a busy return
  2018-06-28 15:46 [PATCH] blk-mq: don't queue more if we get a busy return Jens Axboe
  2018-06-28 17:37 ` Omar Sandoval
@ 2018-06-29  1:59 ` Ming Lei
  2018-06-29  2:18   ` Jens Axboe
  1 sibling, 1 reply; 5+ messages in thread
From: Ming Lei @ 2018-06-29  1:59 UTC (permalink / raw)
  To: Jens Axboe; +Cc: linux-block

On Thu, Jun 28, 2018 at 09:46:50AM -0600, Jens Axboe wrote:
> Some devices have different queue limits depending on the type of IO. A
> classic case is SATA NCQ, where some commands can queue, but others
> cannot. If we have NCQ commands inflight and encounter a non-queueable
> command, the driver returns busy. Currently we attempt to dispatch more
> from the scheduler, if we were able to queue some commands. But for the
> case where we ended up stopping due to BUSY, we should not attempt to
> retrieve more from the scheduler. If we do, we can get into a situation
> where we attempt to queue a non-queueable command, get BUSY, then
> successfully retrieve more commands from that scheduler and queue those.
> This can repeat forever, starving the non-queuable command indefinitely.
> 
> Fix this by NOT attempting to pull more commands from the scheduler, if
> we get a BUSY return. This should also be more optimal in terms of
> letting requests stay in the scheduler for as long as possible, if we
> get a BUSY due to the regular out-of-tags condition.
> 
> Signed-off-by: Jens Axboe <axboe@kernel.dk>
> 
> diff --git a/block/blk-mq.c b/block/blk-mq.c
> index b6888ff556cf..d394cdd8d8c6 100644
> --- a/block/blk-mq.c
> +++ b/block/blk-mq.c
> @@ -1075,6 +1075,9 @@ static bool blk_mq_mark_tag_wait(struct blk_mq_hw_ctx **hctx,
>  
>  #define BLK_MQ_RESOURCE_DELAY	3		/* ms units */
>  
> +/*
> + * Returns true if we did some work AND can potentially do more.
> + */
>  bool blk_mq_dispatch_rq_list(struct request_queue *q, struct list_head *list,
>  			     bool got_budget)
>  {
> @@ -1205,8 +1208,17 @@ bool blk_mq_dispatch_rq_list(struct request_queue *q, struct list_head *list,
>  			blk_mq_run_hw_queue(hctx, true);
>  		else if (needs_restart && (ret == BLK_STS_RESOURCE))
>  			blk_mq_delay_run_hw_queue(hctx, BLK_MQ_RESOURCE_DELAY);
> +
> +		return false;
>  	}
>  
> +	/*
> +	 * If the host/device is unable to accept more work, inform the
> +	 * caller of that.
> +	 */
> +	if (ret == BLK_STS_RESOURCE || ret == BLK_STS_DEV_RESOURCE)
> +		return false;

The above change may not be needed since one invariant is that
!list_empty(list) becomes true if either BLK_STS_RESOURCE or BLK_STS_DEV_RESOURCE
is returned from .queue_rq().

Thanks,
Ming

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] blk-mq: don't queue more if we get a busy return
  2018-06-29  1:59 ` Ming Lei
@ 2018-06-29  2:18   ` Jens Axboe
  2018-06-29  2:44     ` Ming Lei
  0 siblings, 1 reply; 5+ messages in thread
From: Jens Axboe @ 2018-06-29  2:18 UTC (permalink / raw)
  To: Ming Lei; +Cc: linux-block

On 6/28/18 7:59 PM, Ming Lei wrote:
> On Thu, Jun 28, 2018 at 09:46:50AM -0600, Jens Axboe wrote:
>> Some devices have different queue limits depending on the type of IO. A
>> classic case is SATA NCQ, where some commands can queue, but others
>> cannot. If we have NCQ commands inflight and encounter a non-queueable
>> command, the driver returns busy. Currently we attempt to dispatch more
>> from the scheduler, if we were able to queue some commands. But for the
>> case where we ended up stopping due to BUSY, we should not attempt to
>> retrieve more from the scheduler. If we do, we can get into a situation
>> where we attempt to queue a non-queueable command, get BUSY, then
>> successfully retrieve more commands from that scheduler and queue those.
>> This can repeat forever, starving the non-queuable command indefinitely.
>>
>> Fix this by NOT attempting to pull more commands from the scheduler, if
>> we get a BUSY return. This should also be more optimal in terms of
>> letting requests stay in the scheduler for as long as possible, if we
>> get a BUSY due to the regular out-of-tags condition.
>>
>> Signed-off-by: Jens Axboe <axboe@kernel.dk>
>>
>> diff --git a/block/blk-mq.c b/block/blk-mq.c
>> index b6888ff556cf..d394cdd8d8c6 100644
>> --- a/block/blk-mq.c
>> +++ b/block/blk-mq.c
>> @@ -1075,6 +1075,9 @@ static bool blk_mq_mark_tag_wait(struct blk_mq_hw_ctx **hctx,
>>  
>>  #define BLK_MQ_RESOURCE_DELAY	3		/* ms units */
>>  
>> +/*
>> + * Returns true if we did some work AND can potentially do more.
>> + */
>>  bool blk_mq_dispatch_rq_list(struct request_queue *q, struct list_head *list,
>>  			     bool got_budget)
>>  {
>> @@ -1205,8 +1208,17 @@ bool blk_mq_dispatch_rq_list(struct request_queue *q, struct list_head *list,
>>  			blk_mq_run_hw_queue(hctx, true);
>>  		else if (needs_restart && (ret == BLK_STS_RESOURCE))
>>  			blk_mq_delay_run_hw_queue(hctx, BLK_MQ_RESOURCE_DELAY);
>> +
>> +		return false;
>>  	}
>>  
>> +	/*
>> +	 * If the host/device is unable to accept more work, inform the
>> +	 * caller of that.
>> +	 */
>> +	if (ret == BLK_STS_RESOURCE || ret == BLK_STS_DEV_RESOURCE)
>> +		return false;
> 
> The above change may not be needed since one invariant is that
> !list_empty(list) becomes true if either BLK_STS_RESOURCE or BLK_STS_DEV_RESOURCE
> is returned from .queue_rq().

Agree, that's one case, but it's more bullet proof this way. And explicit,
I'd rather not break this odd case again.

-- 
Jens Axboe

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] blk-mq: don't queue more if we get a busy return
  2018-06-29  2:18   ` Jens Axboe
@ 2018-06-29  2:44     ` Ming Lei
  0 siblings, 0 replies; 5+ messages in thread
From: Ming Lei @ 2018-06-29  2:44 UTC (permalink / raw)
  To: Jens Axboe; +Cc: linux-block

On Thu, Jun 28, 2018 at 08:18:04PM -0600, Jens Axboe wrote:
> On 6/28/18 7:59 PM, Ming Lei wrote:
> > On Thu, Jun 28, 2018 at 09:46:50AM -0600, Jens Axboe wrote:
> >> Some devices have different queue limits depending on the type of IO. A
> >> classic case is SATA NCQ, where some commands can queue, but others
> >> cannot. If we have NCQ commands inflight and encounter a non-queueable
> >> command, the driver returns busy. Currently we attempt to dispatch more
> >> from the scheduler, if we were able to queue some commands. But for the
> >> case where we ended up stopping due to BUSY, we should not attempt to
> >> retrieve more from the scheduler. If we do, we can get into a situation
> >> where we attempt to queue a non-queueable command, get BUSY, then
> >> successfully retrieve more commands from that scheduler and queue those.
> >> This can repeat forever, starving the non-queuable command indefinitely.
> >>
> >> Fix this by NOT attempting to pull more commands from the scheduler, if
> >> we get a BUSY return. This should also be more optimal in terms of
> >> letting requests stay in the scheduler for as long as possible, if we
> >> get a BUSY due to the regular out-of-tags condition.
> >>
> >> Signed-off-by: Jens Axboe <axboe@kernel.dk>
> >>
> >> diff --git a/block/blk-mq.c b/block/blk-mq.c
> >> index b6888ff556cf..d394cdd8d8c6 100644
> >> --- a/block/blk-mq.c
> >> +++ b/block/blk-mq.c
> >> @@ -1075,6 +1075,9 @@ static bool blk_mq_mark_tag_wait(struct blk_mq_hw_ctx **hctx,
> >>  
> >>  #define BLK_MQ_RESOURCE_DELAY	3		/* ms units */
> >>  
> >> +/*
> >> + * Returns true if we did some work AND can potentially do more.
> >> + */
> >>  bool blk_mq_dispatch_rq_list(struct request_queue *q, struct list_head *list,
> >>  			     bool got_budget)
> >>  {
> >> @@ -1205,8 +1208,17 @@ bool blk_mq_dispatch_rq_list(struct request_queue *q, struct list_head *list,
> >>  			blk_mq_run_hw_queue(hctx, true);
> >>  		else if (needs_restart && (ret == BLK_STS_RESOURCE))
> >>  			blk_mq_delay_run_hw_queue(hctx, BLK_MQ_RESOURCE_DELAY);
> >> +
> >> +		return false;
> >>  	}
> >>  
> >> +	/*
> >> +	 * If the host/device is unable to accept more work, inform the
> >> +	 * caller of that.
> >> +	 */
> >> +	if (ret == BLK_STS_RESOURCE || ret == BLK_STS_DEV_RESOURCE)
> >> +		return false;
> > 
> > The above change may not be needed since one invariant is that
> > !list_empty(list) becomes true if either BLK_STS_RESOURCE or BLK_STS_DEV_RESOURCE
> > is returned from .queue_rq().
> 
> Agree, that's one case, but it's more bullet proof this way. And explicit,
> I'd rather not break this odd case again.

OK, just two-line dead code, not a big deal.

I guess this patch may improve sequential IO performance a bit on SCSI HDD.,
so:

Reviewed-by: Ming Lei <ming.lei@redhat.com>

Thanks,
Ming

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2018-06-29  2:44 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-06-28 15:46 [PATCH] blk-mq: don't queue more if we get a busy return Jens Axboe
2018-06-28 17:37 ` Omar Sandoval
2018-06-29  1:59 ` Ming Lei
2018-06-29  2:18   ` Jens Axboe
2018-06-29  2:44     ` Ming Lei

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.