Skip to content

Commit 0471559

Browse files
Algodev-githubaxboe
authored andcommitted
block, bfq: add/remove entity weights correctly
To keep I/O throughput high as often as possible, BFQ performs I/O-dispatch plugging (aka device idling) only when beneficial exactly for throughput, or when needed for service guarantees (low latency, fairness). An important case where the latter condition holds is when the scenario is 'asymmetric' in terms of weights: i.e., when some bfq_queue or whole group of queues has a higher weight, and thus has to receive more service, than other queues or groups. Without dispatch plugging, lower-weight queues/groups may unjustly steal bandwidth to higher-weight queues/groups. To detect asymmetric scenarios, BFQ checks some sufficient conditions. One of these conditions is that active groups have different weights. BFQ controls this condition by maintaining a special set of unique weights of active groups (group_weights_tree). To this purpose, in the function bfq_active_insert/bfq_active_extract BFQ adds/removes the weight of a group to/from this set. Unfortunately, the function bfq_active_extract may happen to be invoked also for a group that is still active (to preserve the correct update of the next queue to serve, see comments in function bfq_no_longer_next_in_service() for details). In this case, removing the weight of the group makes the set group_weights_tree inconsistent. Service-guarantee violations follow. This commit addresses this issue by moving group_weights_tree insertions from their previous location (in bfq_active_insert) into the function __bfq_activate_entity, and by moving group_weights_tree extractions from bfq_active_extract to when the entity that represents a group remains throughly idle, i.e., with no request either enqueued or dispatched. Tested-by: Holger Hoffstätte <holger@applied-asynchrony.com> Tested-by: Oleksandr Natalenko <oleksandr@natalenko.name> Signed-off-by: Paolo Valente <paolo.valente@linaro.org> Signed-off-by: Jens Axboe <axboe@kernel.dk>
1 parent 6a5ac98 commit 0471559

File tree

3 files changed

+59
-17
lines changed

3 files changed

+59
-17
lines changed

block/bfq-iosched.c

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -742,8 +742,9 @@ void bfq_weights_tree_add(struct bfq_data *bfqd, struct bfq_entity *entity,
742742
* See the comments to the function bfq_weights_tree_add() for considerations
743743
* about overhead.
744744
*/
745-
void bfq_weights_tree_remove(struct bfq_data *bfqd, struct bfq_entity *entity,
746-
struct rb_root *root)
745+
void __bfq_weights_tree_remove(struct bfq_data *bfqd,
746+
struct bfq_entity *entity,
747+
struct rb_root *root)
747748
{
748749
if (!entity->weight_counter)
749750
return;
@@ -759,6 +760,43 @@ void bfq_weights_tree_remove(struct bfq_data *bfqd, struct bfq_entity *entity,
759760
entity->weight_counter = NULL;
760761
}
761762

763+
/*
764+
* Invoke __bfq_weights_tree_remove on bfqq and all its inactive
765+
* parent entities.
766+
*/
767+
void bfq_weights_tree_remove(struct bfq_data *bfqd,
768+
struct bfq_queue *bfqq)
769+
{
770+
struct bfq_entity *entity = bfqq->entity.parent;
771+
772+
__bfq_weights_tree_remove(bfqd, &bfqq->entity,
773+
&bfqd->queue_weights_tree);
774+
775+
for_each_entity(entity) {
776+
struct bfq_sched_data *sd = entity->my_sched_data;
777+
778+
if (sd->next_in_service || sd->in_service_entity) {
779+
/*
780+
* entity is still active, because either
781+
* next_in_service or in_service_entity is not
782+
* NULL (see the comments on the definition of
783+
* next_in_service for details on why
784+
* in_service_entity must be checked too).
785+
*
786+
* As a consequence, the weight of entity is
787+
* not to be removed. In addition, if entity
788+
* is active, then its parent entities are
789+
* active as well, and thus their weights are
790+
* not to be removed either. In the end, this
791+
* loop must stop here.
792+
*/
793+
break;
794+
}
795+
__bfq_weights_tree_remove(bfqd, entity,
796+
&bfqd->group_weights_tree);
797+
}
798+
}
799+
762800
/*
763801
* Return expired entry, or NULL to just start from scratch in rbtree.
764802
*/
@@ -4582,8 +4620,7 @@ static void bfq_completed_request(struct bfq_queue *bfqq, struct bfq_data *bfqd)
45824620
*/
45834621
bfqq->budget_timeout = jiffies;
45844622

4585-
bfq_weights_tree_remove(bfqd, &bfqq->entity,
4586-
&bfqd->queue_weights_tree);
4623+
bfq_weights_tree_remove(bfqd, bfqq);
45874624
}
45884625

45894626
now_ns = ktime_get_ns();

block/bfq-iosched.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -827,8 +827,11 @@ struct bfq_data *bic_to_bfqd(struct bfq_io_cq *bic);
827827
void bfq_pos_tree_add_move(struct bfq_data *bfqd, struct bfq_queue *bfqq);
828828
void bfq_weights_tree_add(struct bfq_data *bfqd, struct bfq_entity *entity,
829829
struct rb_root *root);
830-
void bfq_weights_tree_remove(struct bfq_data *bfqd, struct bfq_entity *entity,
831-
struct rb_root *root);
830+
void __bfq_weights_tree_remove(struct bfq_data *bfqd,
831+
struct bfq_entity *entity,
832+
struct rb_root *root);
833+
void bfq_weights_tree_remove(struct bfq_data *bfqd,
834+
struct bfq_queue *bfqq);
832835
void bfq_bfqq_expire(struct bfq_data *bfqd, struct bfq_queue *bfqq,
833836
bool compensate, enum bfqq_expiration reason);
834837
void bfq_put_queue(struct bfq_queue *bfqq);

block/bfq-wf2q.c

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -499,9 +499,6 @@ static void bfq_active_insert(struct bfq_service_tree *st,
499499
if (bfqq)
500500
list_add(&bfqq->bfqq_list, &bfqq->bfqd->active_list);
501501
#ifdef CONFIG_BFQ_GROUP_IOSCHED
502-
else /* bfq_group */
503-
bfq_weights_tree_add(bfqd, entity, &bfqd->group_weights_tree);
504-
505502
if (bfqg != bfqd->root_group)
506503
bfqg->active_entities++;
507504
#endif
@@ -601,10 +598,6 @@ static void bfq_active_extract(struct bfq_service_tree *st,
601598
if (bfqq)
602599
list_del(&bfqq->bfqq_list);
603600
#ifdef CONFIG_BFQ_GROUP_IOSCHED
604-
else /* bfq_group */
605-
bfq_weights_tree_remove(bfqd, entity,
606-
&bfqd->group_weights_tree);
607-
608601
if (bfqg != bfqd->root_group)
609602
bfqg->active_entities--;
610603
#endif
@@ -799,7 +792,7 @@ __bfq_entity_update_weight_prio(struct bfq_service_tree *old_st,
799792
if (prev_weight != new_weight) {
800793
root = bfqq ? &bfqd->queue_weights_tree :
801794
&bfqd->group_weights_tree;
802-
bfq_weights_tree_remove(bfqd, entity, root);
795+
__bfq_weights_tree_remove(bfqd, entity, root);
803796
}
804797
entity->weight = new_weight;
805798
/*
@@ -971,7 +964,7 @@ static void bfq_update_fin_time_enqueue(struct bfq_entity *entity,
971964
* one of its children receives a new request.
972965
*
973966
* Basically, this function updates the timestamps of entity and
974-
* inserts entity into its active tree, ater possibly extracting it
967+
* inserts entity into its active tree, after possibly extracting it
975968
* from its idle tree.
976969
*/
977970
static void __bfq_activate_entity(struct bfq_entity *entity,
@@ -1015,6 +1008,16 @@ static void __bfq_activate_entity(struct bfq_entity *entity,
10151008
entity->on_st = true;
10161009
}
10171010

1011+
#ifdef BFQ_GROUP_IOSCHED_ENABLED
1012+
if (!bfq_entity_to_bfqq(entity)) { /* bfq_group */
1013+
struct bfq_group *bfqg =
1014+
container_of(entity, struct bfq_group, entity);
1015+
1016+
bfq_weights_tree_add(bfqg->bfqd, entity,
1017+
&bfqd->group_weights_tree);
1018+
}
1019+
#endif
1020+
10181021
bfq_update_fin_time_enqueue(entity, st, backshifted);
10191022
}
10201023

@@ -1664,8 +1667,7 @@ void bfq_del_bfqq_busy(struct bfq_data *bfqd, struct bfq_queue *bfqq,
16641667
bfqd->busy_queues--;
16651668

16661669
if (!bfqq->dispatched)
1667-
bfq_weights_tree_remove(bfqd, &bfqq->entity,
1668-
&bfqd->queue_weights_tree);
1670+
bfq_weights_tree_remove(bfqd, bfqq);
16691671

16701672
if (bfqq->wr_coeff > 1)
16711673
bfqd->wr_busy_queues--;

0 commit comments

Comments
 (0)