| From 73f04238f21a5510ebcf4ef614fd76a575827fad Mon Sep 17 00:00:00 2001 |
| From: Paolo Valente <paolo.valente@linaro.org> |
| Date: Sat, 21 Mar 2020 10:45:20 +0100 |
| Subject: [PATCH] block, bfq: make reparent_leaf_entity actually work only on |
| leaf entities |
| |
| commit 576682fa52cbd95deb3773449566274f206acc58 upstream. |
| |
| bfq_reparent_leaf_entity() reparents the input leaf entity (a leaf |
| entity represents just a bfq_queue in an entity tree). Yet, the input |
| entity is guaranteed to always be a leaf entity only in two-level |
| entity trees. In this respect, because of the error fixed by |
| commit 14afc5936197 ("block, bfq: fix overwrite of bfq_group pointer |
| in bfq_find_set_group()"), all (wrongly collapsed) entity trees happened |
| to actually have only two levels. After the latter commit, this does not |
| hold any longer. |
| |
| This commit fixes this problem by modifying |
| bfq_reparent_leaf_entity(), so that it searches an active leaf entity |
| down the path that stems from the input entity. Such a leaf entity is |
| guaranteed to exist when bfq_reparent_leaf_entity() is invoked. |
| |
| Tested-by: cki-project@redhat.com |
| Signed-off-by: Paolo Valente <paolo.valente@linaro.org> |
| Signed-off-by: Jens Axboe <axboe@kernel.dk> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/block/bfq-cgroup.c b/block/bfq-cgroup.c |
| index 280a0b8c537d..6df4cb195ed4 100644 |
| --- a/block/bfq-cgroup.c |
| +++ b/block/bfq-cgroup.c |
| @@ -721,39 +721,53 @@ static void bfq_flush_idle_tree(struct bfq_service_tree *st) |
| /** |
| * bfq_reparent_leaf_entity - move leaf entity to the root_group. |
| * @bfqd: the device data structure with the root group. |
| - * @entity: the entity to move. |
| + * @entity: the entity to move, if entity is a leaf; or the parent entity |
| + * of an active leaf entity to move, if entity is not a leaf. |
| */ |
| static void bfq_reparent_leaf_entity(struct bfq_data *bfqd, |
| - struct bfq_entity *entity) |
| + struct bfq_entity *entity, |
| + int ioprio_class) |
| { |
| - struct bfq_queue *bfqq = bfq_entity_to_bfqq(entity); |
| + struct bfq_queue *bfqq; |
| + struct bfq_entity *child_entity = entity; |
| + |
| + while (child_entity->my_sched_data) { /* leaf not reached yet */ |
| + struct bfq_sched_data *child_sd = child_entity->my_sched_data; |
| + struct bfq_service_tree *child_st = child_sd->service_tree + |
| + ioprio_class; |
| + struct rb_root *child_active = &child_st->active; |
| |
| + child_entity = bfq_entity_of(rb_first(child_active)); |
| + |
| + if (!child_entity) |
| + child_entity = child_sd->in_service_entity; |
| + } |
| + |
| + bfqq = bfq_entity_to_bfqq(child_entity); |
| bfq_bfqq_move(bfqd, bfqq, bfqd->root_group); |
| } |
| |
| /** |
| - * bfq_reparent_active_entities - move to the root group all active |
| - * entities. |
| + * bfq_reparent_active_queues - move to the root group all active queues. |
| * @bfqd: the device data structure with the root group. |
| * @bfqg: the group to move from. |
| - * @st: the service tree with the entities. |
| + * @st: the service tree to start the search from. |
| */ |
| -static void bfq_reparent_active_entities(struct bfq_data *bfqd, |
| - struct bfq_group *bfqg, |
| - struct bfq_service_tree *st) |
| +static void bfq_reparent_active_queues(struct bfq_data *bfqd, |
| + struct bfq_group *bfqg, |
| + struct bfq_service_tree *st, |
| + int ioprio_class) |
| { |
| struct rb_root *active = &st->active; |
| - struct bfq_entity *entity = NULL; |
| - |
| - if (!RB_EMPTY_ROOT(&st->active)) |
| - entity = bfq_entity_of(rb_first(active)); |
| + struct bfq_entity *entity; |
| |
| - for (; entity ; entity = bfq_entity_of(rb_first(active))) |
| - bfq_reparent_leaf_entity(bfqd, entity); |
| + while ((entity = bfq_entity_of(rb_first(active)))) |
| + bfq_reparent_leaf_entity(bfqd, entity, ioprio_class); |
| |
| if (bfqg->sched_data.in_service_entity) |
| bfq_reparent_leaf_entity(bfqd, |
| - bfqg->sched_data.in_service_entity); |
| + bfqg->sched_data.in_service_entity, |
| + ioprio_class); |
| } |
| |
| /** |
| @@ -804,7 +818,7 @@ static void bfq_pd_offline(struct blkg_policy_data *pd) |
| * There is no need to put the sync queues, as the |
| * scheduler has taken no reference. |
| */ |
| - bfq_reparent_active_entities(bfqd, bfqg, st); |
| + bfq_reparent_active_queues(bfqd, bfqg, st, i); |
| } |
| |
| __bfq_deactivate_entity(entity, false); |
| -- |
| 2.7.4 |
| |