Skip to content

Commit 431b17f

Browse files
Algodev-githubaxboe
authored andcommitted
block, bfq: don't change ioprio class for a bfq_queue on a service tree
On each deactivation or re-scheduling (after being served) of a bfq_queue, BFQ invokes the function __bfq_entity_update_weight_prio(), to perform pending updates of ioprio, weight and ioprio class for the bfq_queue. BFQ also invokes this function on I/O-request dispatches, to raise or lower weights more quickly when needed, thereby improving latency. However, the entity representing the bfq_queue may be on the active (sub)tree of a service tree when this happens, and, although with a very low probability, the bfq_queue may happen to also have a pending change of its ioprio class. If both conditions hold when __bfq_entity_update_weight_prio() is invoked, then the entity moves to a sort of hybrid state: the new service tree for the entity, as returned by bfq_entity_service_tree(), differs from service tree on which the entity still is. The functions that handle activations and deactivations of entities do not cope with such a hybrid state (and would need to become more complex to cope). This commit addresses this issue by just making __bfq_entity_update_weight_prio() not perform also a possible pending change of ioprio class, when invoked on an I/O-request dispatch for a bfq_queue. Such a change is thus postponed to when __bfq_entity_update_weight_prio() is invoked on deactivation or re-scheduling of the bfq_queue. Reported-by: Marco Piazza <[email protected]> Reported-by: Laurentiu Nicola <[email protected]> Signed-off-by: Paolo Valente <[email protected]> Tested-by: Marco Piazza <[email protected]> Signed-off-by: Jens Axboe <[email protected]>
1 parent 7a69f9c commit 431b17f

File tree

3 files changed

+46
-10
lines changed

3 files changed

+46
-10
lines changed

block/bfq-iosched.c

+10-4
Original file line numberDiff line numberDiff line change
@@ -3483,11 +3483,17 @@ static void bfq_update_wr_data(struct bfq_data *bfqd, struct bfq_queue *bfqq)
34833483
}
34843484
}
34853485
}
3486-
/* Update weight both if it must be raised and if it must be lowered */
3486+
/*
3487+
* To improve latency (for this or other queues), immediately
3488+
* update weight both if it must be raised and if it must be
3489+
* lowered. Since, entity may be on some active tree here, and
3490+
* might have a pending change of its ioprio class, invoke
3491+
* next function with the last parameter unset (see the
3492+
* comments on the function).
3493+
*/
34873494
if ((entity->weight > entity->orig_weight) != (bfqq->wr_coeff > 1))
3488-
__bfq_entity_update_weight_prio(
3489-
bfq_entity_service_tree(entity),
3490-
entity);
3495+
__bfq_entity_update_weight_prio(bfq_entity_service_tree(entity),
3496+
entity, false);
34913497
}
34923498

34933499
/*

block/bfq-iosched.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -892,7 +892,8 @@ void bfq_put_idle_entity(struct bfq_service_tree *st,
892892
struct bfq_entity *entity);
893893
struct bfq_service_tree *
894894
__bfq_entity_update_weight_prio(struct bfq_service_tree *old_st,
895-
struct bfq_entity *entity);
895+
struct bfq_entity *entity,
896+
bool update_class_too);
896897
void bfq_bfqq_served(struct bfq_queue *bfqq, int served);
897898
void bfq_bfqq_charge_time(struct bfq_data *bfqd, struct bfq_queue *bfqq,
898899
unsigned long time_ms);

block/bfq-wf2q.c

+34-5
Original file line numberDiff line numberDiff line change
@@ -694,10 +694,28 @@ struct bfq_service_tree *bfq_entity_service_tree(struct bfq_entity *entity)
694694
return sched_data->service_tree + idx;
695695
}
696696

697-
697+
/*
698+
* Update weight and priority of entity. If update_class_too is true,
699+
* then update the ioprio_class of entity too.
700+
*
701+
* The reason why the update of ioprio_class is controlled through the
702+
* last parameter is as follows. Changing the ioprio class of an
703+
* entity implies changing the destination service trees for that
704+
* entity. If such a change occurred when the entity is already on one
705+
* of the service trees for its previous class, then the state of the
706+
* entity would become more complex: none of the new possible service
707+
* trees for the entity, according to bfq_entity_service_tree(), would
708+
* match any of the possible service trees on which the entity
709+
* is. Complex operations involving these trees, such as entity
710+
* activations and deactivations, should take into account this
711+
* additional complexity. To avoid this issue, this function is
712+
* invoked with update_class_too unset in the points in the code where
713+
* entity may happen to be on some tree.
714+
*/
698715
struct bfq_service_tree *
699716
__bfq_entity_update_weight_prio(struct bfq_service_tree *old_st,
700-
struct bfq_entity *entity)
717+
struct bfq_entity *entity,
718+
bool update_class_too)
701719
{
702720
struct bfq_service_tree *new_st = old_st;
703721

@@ -739,9 +757,15 @@ __bfq_entity_update_weight_prio(struct bfq_service_tree *old_st,
739757
bfq_weight_to_ioprio(entity->orig_weight);
740758
}
741759

742-
if (bfqq)
760+
if (bfqq && update_class_too)
743761
bfqq->ioprio_class = bfqq->new_ioprio_class;
744-
entity->prio_changed = 0;
762+
763+
/*
764+
* Reset prio_changed only if the ioprio_class change
765+
* is not pending any longer.
766+
*/
767+
if (!bfqq || bfqq->ioprio_class == bfqq->new_ioprio_class)
768+
entity->prio_changed = 0;
745769

746770
/*
747771
* NOTE: here we may be changing the weight too early,
@@ -867,7 +891,12 @@ static void bfq_update_fin_time_enqueue(struct bfq_entity *entity,
867891
{
868892
struct bfq_queue *bfqq = bfq_entity_to_bfqq(entity);
869893

870-
st = __bfq_entity_update_weight_prio(st, entity);
894+
/*
895+
* When this function is invoked, entity is not in any service
896+
* tree, then it is safe to invoke next function with the last
897+
* parameter set (see the comments on the function).
898+
*/
899+
st = __bfq_entity_update_weight_prio(st, entity, true);
871900
bfq_calc_finish(entity, entity->budget);
872901

873902
/*

0 commit comments

Comments
 (0)