block, bfq: put reqs of waker and woken in dispatch list
Consider a new I/O request that arrives for a bfq_queue bfqq. If, when this happens, the only active bfq_queues are bfqq and either its waker bfq_queue or one of its woken bfq_queues, then there is no point in queueing this new I/O request in bfqq for service. In fact, the in-service queue and bfqq agree on serving this new I/O request as soon as possible. So this commit puts this new I/O request directly into the dispatch list. Tested-by: Jan Kara <jack@suse.cz> Acked-by: Jan Kara <jack@suse.cz> Signed-off-by: Paolo Valente <paolo.valente@linaro.org> Tested-by: Oleksandr Natalenko <oleksandr@natalenko.name> Link: https://lore.kernel.org/r/20210304174627.161-3-paolo.valente@linaro.org Signed-off-by: Jens Axboe <axboe@kernel.dk>
This commit is contained in:
parent
2ec5a5c483
commit
7cc4ffc555
|
@ -5649,7 +5649,49 @@ static void bfq_insert_request(struct blk_mq_hw_ctx *hctx, struct request *rq,
|
|||
|
||||
spin_lock_irq(&bfqd->lock);
|
||||
bfqq = bfq_init_rq(rq);
|
||||
if (!bfqq || at_head || blk_rq_is_passthrough(rq)) {
|
||||
|
||||
/*
|
||||
* Reqs with at_head or passthrough flags set are to be put
|
||||
* directly into dispatch list. Additional case for putting rq
|
||||
* directly into the dispatch queue: the only active
|
||||
* bfq_queues are bfqq and either its waker bfq_queue or one
|
||||
* of its woken bfq_queues. The rationale behind this
|
||||
* additional condition is as follows:
|
||||
* - consider a bfq_queue, say Q1, detected as a waker of
|
||||
* another bfq_queue, say Q2
|
||||
* - by definition of a waker, Q1 blocks the I/O of Q2, i.e.,
|
||||
* some I/O of Q1 needs to be completed for new I/O of Q2
|
||||
* to arrive. A notable example of waker is journald
|
||||
* - so, Q1 and Q2 are in any respect the queues of two
|
||||
* cooperating processes (or of two cooperating sets of
|
||||
* processes): the goal of Q1's I/O is doing what needs to
|
||||
* be done so that new Q2's I/O can finally be
|
||||
* issued. Therefore, if the service of Q1's I/O is delayed,
|
||||
* then Q2's I/O is delayed too. Conversely, if Q2's I/O is
|
||||
* delayed, the goal of Q1's I/O is hindered.
|
||||
* - as a consequence, if some I/O of Q1/Q2 arrives while
|
||||
* Q2/Q1 is the only queue in service, there is absolutely
|
||||
* no point in delaying the service of such an I/O. The
|
||||
* only possible result is a throughput loss
|
||||
* - so, when the above condition holds, the best option is to
|
||||
* have the new I/O dispatched as soon as possible
|
||||
* - the most effective and efficient way to attain the above
|
||||
* goal is to put the new I/O directly in the dispatch
|
||||
* list
|
||||
* - as an additional restriction, Q1 and Q2 must be the only
|
||||
* busy queues for this commit to put the I/O of Q2/Q1 in
|
||||
* the dispatch list. This is necessary, because, if also
|
||||
* other queues are waiting for service, then putting new
|
||||
* I/O directly in the dispatch list may evidently cause a
|
||||
* violation of service guarantees for the other queues
|
||||
*/
|
||||
if (!bfqq ||
|
||||
(bfqq != bfqd->in_service_queue &&
|
||||
bfqd->in_service_queue != NULL &&
|
||||
bfq_tot_busy_queues(bfqd) == 1 + bfq_bfqq_busy(bfqq) &&
|
||||
(bfqq->waker_bfqq == bfqd->in_service_queue ||
|
||||
bfqd->in_service_queue->waker_bfqq == bfqq)) ||
|
||||
at_head || blk_rq_is_passthrough(rq)) {
|
||||
if (at_head)
|
||||
list_add(&rq->queuelist, &bfqd->dispatch);
|
||||
else
|
||||
|
|
Loading…
Reference in New Issue