diff options
author | Paolo Valente <paolo.valente@linaro.org> | 2017-07-03 04:00:10 -0400 |
---|---|---|
committer | Jens Axboe <axboe@kernel.dk> | 2017-07-03 18:50:00 -0400 |
commit | 431b17f9d5453533cba7d73e7e40428e4f90b35d (patch) | |
tree | e42cf25bcbfbc315f6b4fc3660dce0890cfdbbe2 /block | |
parent | 7a69f9c60b49699579f5bfb71f928cceba0afe1a (diff) |
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 <mpiazza@gmail.com>
Reported-by: Laurentiu Nicola <lnicola@dend.ro>
Signed-off-by: Paolo Valente <paolo.valente@linaro.org>
Tested-by: Marco Piazza <mpiazza@gmail.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Diffstat (limited to 'block')
-rw-r--r-- | block/bfq-iosched.c | 14 | ||||
-rw-r--r-- | block/bfq-iosched.h | 3 | ||||
-rw-r--r-- | block/bfq-wf2q.c | 39 |
3 files changed, 46 insertions, 10 deletions
diff --git a/block/bfq-iosched.c b/block/bfq-iosched.c index 12bbc6b8657d..60a6835265fc 100644 --- a/block/bfq-iosched.c +++ b/block/bfq-iosched.c | |||
@@ -3483,11 +3483,17 @@ static void bfq_update_wr_data(struct bfq_data *bfqd, struct bfq_queue *bfqq) | |||
3483 | } | 3483 | } |
3484 | } | 3484 | } |
3485 | } | 3485 | } |
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 | */ | ||
3487 | if ((entity->weight > entity->orig_weight) != (bfqq->wr_coeff > 1)) | 3494 | if ((entity->weight > entity->orig_weight) != (bfqq->wr_coeff > 1)) |
3488 | __bfq_entity_update_weight_prio( | 3495 | __bfq_entity_update_weight_prio(bfq_entity_service_tree(entity), |
3489 | bfq_entity_service_tree(entity), | 3496 | entity, false); |
3490 | entity); | ||
3491 | } | 3497 | } |
3492 | 3498 | ||
3493 | /* | 3499 | /* |
diff --git a/block/bfq-iosched.h b/block/bfq-iosched.h index 5c3bf9861492..8fd83b885774 100644 --- a/block/bfq-iosched.h +++ b/block/bfq-iosched.h | |||
@@ -892,7 +892,8 @@ void bfq_put_idle_entity(struct bfq_service_tree *st, | |||
892 | struct bfq_entity *entity); | 892 | struct bfq_entity *entity); |
893 | struct bfq_service_tree * | 893 | struct bfq_service_tree * |
894 | __bfq_entity_update_weight_prio(struct bfq_service_tree *old_st, | 894 | __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); | ||
896 | void bfq_bfqq_served(struct bfq_queue *bfqq, int served); | 897 | void bfq_bfqq_served(struct bfq_queue *bfqq, int served); |
897 | void bfq_bfqq_charge_time(struct bfq_data *bfqd, struct bfq_queue *bfqq, | 898 | void bfq_bfqq_charge_time(struct bfq_data *bfqd, struct bfq_queue *bfqq, |
898 | unsigned long time_ms); | 899 | unsigned long time_ms); |
diff --git a/block/bfq-wf2q.c b/block/bfq-wf2q.c index 8726ede19eef..5ec05cd42b80 100644 --- a/block/bfq-wf2q.c +++ b/block/bfq-wf2q.c | |||
@@ -694,10 +694,28 @@ struct bfq_service_tree *bfq_entity_service_tree(struct bfq_entity *entity) | |||
694 | return sched_data->service_tree + idx; | 694 | return sched_data->service_tree + idx; |
695 | } | 695 | } |
696 | 696 | ||
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 | */ | ||
698 | struct bfq_service_tree * | 715 | struct bfq_service_tree * |
699 | __bfq_entity_update_weight_prio(struct bfq_service_tree *old_st, | 716 | __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) | ||
701 | { | 719 | { |
702 | struct bfq_service_tree *new_st = old_st; | 720 | struct bfq_service_tree *new_st = old_st; |
703 | 721 | ||
@@ -739,9 +757,15 @@ __bfq_entity_update_weight_prio(struct bfq_service_tree *old_st, | |||
739 | bfq_weight_to_ioprio(entity->orig_weight); | 757 | bfq_weight_to_ioprio(entity->orig_weight); |
740 | } | 758 | } |
741 | 759 | ||
742 | if (bfqq) | 760 | if (bfqq && update_class_too) |
743 | bfqq->ioprio_class = bfqq->new_ioprio_class; | 761 | 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; | ||
745 | 769 | ||
746 | /* | 770 | /* |
747 | * NOTE: here we may be changing the weight too early, | 771 | * 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, | |||
867 | { | 891 | { |
868 | struct bfq_queue *bfqq = bfq_entity_to_bfqq(entity); | 892 | struct bfq_queue *bfqq = bfq_entity_to_bfqq(entity); |
869 | 893 | ||
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); | ||
871 | bfq_calc_finish(entity, entity->budget); | 900 | bfq_calc_finish(entity, entity->budget); |
872 | 901 | ||
873 | /* | 902 | /* |