Skip to content

Commit

Permalink
block, bfq: fix service being wrongly set to zero in case of preemption
Browse files Browse the repository at this point in the history
If
- a bfq_queue Q preempts another queue, because one request of Q
arrives in time,
- but, after this preemption, Q is not the queue that is set in service,
then Q->entity.service is set to 0 when Q is eventually set in
service. But Q should have continued receiving service with its old
budget (which is why preemption has occurred) and its old service.

This commit addresses this issue by resetting service on queue real
expiration.

Tested-by: Holger Hoffstätte <[email protected]>
Tested-by: Oleksandr Natalenko <[email protected]>
Signed-off-by: Paolo Valente <[email protected]>
Signed-off-by: Jens Axboe <[email protected]>
  • Loading branch information
Algodev-github authored and axboe committed Jul 9, 2018
1 parent 4420b09 commit 9fae8dd
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 12 deletions.
34 changes: 28 additions & 6 deletions block/bfq-iosched.c
Original file line number Diff line number Diff line change
Expand Up @@ -1382,18 +1382,30 @@ static bool bfq_bfqq_update_budg_for_activation(struct bfq_data *bfqd,
* remain unchanged after such an expiration, and the
* following statement therefore assigns to
* entity->budget the remaining budget on such an
* expiration. For clarity, entity->service is not
* updated on expiration in any case, and, in normal
* operation, is reset only when bfqq is selected for
* service (see bfq_get_next_queue).
* expiration.
*/
entity->budget = min_t(unsigned long,
bfq_bfqq_budget_left(bfqq),
bfqq->max_budget);

/*
* At this point, we have used entity->service to get
* the budget left (needed for updating
* entity->budget). Thus we finally can, and have to,
* reset entity->service. The latter must be reset
* because bfqq would otherwise be charged again for
* the service it has received during its previous
* service slot(s).
*/
entity->service = 0;

return true;
}

/*
* We can finally complete expiration, by setting service to 0.
*/
entity->service = 0;
entity->budget = max_t(unsigned long, bfqq->max_budget,
bfq_serv_to_charge(bfqq->next_rq, bfqq));
bfq_clear_bfqq_non_blocking_wait_rq(bfqq);
Expand Down Expand Up @@ -3271,11 +3283,21 @@ void bfq_bfqq_expire(struct bfq_data *bfqd,
ref = bfqq->ref;
__bfq_bfqq_expire(bfqd, bfqq);

if (ref == 1) /* bfqq is gone, no more actions on it */
return;

/* mark bfqq as waiting a request only if a bic still points to it */
if (ref > 1 && !bfq_bfqq_busy(bfqq) &&
if (!bfq_bfqq_busy(bfqq) &&
reason != BFQQE_BUDGET_TIMEOUT &&
reason != BFQQE_BUDGET_EXHAUSTED)
reason != BFQQE_BUDGET_EXHAUSTED) {
bfq_mark_bfqq_non_blocking_wait_rq(bfqq);
/*
* Not setting service to 0, because, if the next rq
* arrives in time, the queue will go on receiving
* service with this same budget (as if it never expired)
*/
} else
entity->service = 0;
}

/*
Expand Down
6 changes: 0 additions & 6 deletions block/bfq-wf2q.c
Original file line number Diff line number Diff line change
Expand Up @@ -1544,12 +1544,6 @@ struct bfq_queue *bfq_get_next_queue(struct bfq_data *bfqd)
entity = sd->next_in_service;
sd->in_service_entity = entity;

/*
* Reset the accumulator of the amount of service that
* the entity is about to receive.
*/
entity->service = 0;

/*
* If entity is no longer a candidate for next
* service, then it must be extracted from its active
Expand Down

0 comments on commit 9fae8dd

Please sign in to comment.