Commit 576682fa authored by Paolo Valente's avatar Paolo Valente Committed by Jens Axboe
Browse files

block, bfq: make reparent_leaf_entity actually work only on leaf entities



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 14afc593 ("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: default avatar <cki-project@redhat.com>
Signed-off-by: default avatarPaolo Valente <paolo.valente@linaro.org>
Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent c8997736
Loading
Loading
Loading
Loading
+31 −17
Original line number Diff line number Diff line
@@ -815,39 +815,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,
static void bfq_reparent_active_queues(struct bfq_data *bfqd,
				       struct bfq_group *bfqg,
					 struct bfq_service_tree *st)
				       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);
}

/**
@@ -898,7 +912,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);