blob: 69e95a607fd8b9d609ea4cf459586fc8732dffcc [file] [log] [blame]
From 99fec430f7028454bcaa2bef75357cada98e3044 Mon Sep 17 00:00:00 2001
From: Carlo Nonato <>
Date: Fri, 6 Mar 2020 13:27:31 +0100
Subject: [PATCH] block, bfq: fix overwrite of bfq_group pointer in
commit 14afc59361976c0ba39e3a9589c3eaa43ebc7e1d upstream.
The bfq_find_set_group() function takes as input a blkcg (which represents
a cgroup) and retrieves the corresponding bfq_group, then it updates the
bfq internal group hierarchy (see comments inside the function for why
this is needed) and finally it returns the bfq_group.
In the hierarchy update cycle, the pointer holding the correct bfq_group
that has to be returned is mistakenly used to traverse the hierarchy
bottom to top, meaning that in each iteration it gets overwritten with the
parent of the current group. Since the update cycle stops at root's
children (depth = 2), the overwrite becomes a problem only if the blkcg
describes a cgroup at a hierarchy level deeper than that (depth > 2). In
this case the root's child that happens to be also an ancestor of the
correct bfq_group is returned. The main consequence is that processes
contained in a cgroup at depth greater than 2 are wrongly placed in the
group described above by BFQ.
This commits fixes this problem by using a different bfq_group pointer in
the update cycle in order to avoid the overwrite of the variable holding
the original group reference.
Reported-by: Kwon Je Oh <>
Signed-off-by: Carlo Nonato <>
Signed-off-by: Paolo Valente <>
Signed-off-by: Jens Axboe <>
Signed-off-by: Paul Gortmaker <>
diff --git a/block/bfq-cgroup.c b/block/bfq-cgroup.c
index 0ad66e52ce19..31f29db65a89 100644
--- a/block/bfq-cgroup.c
+++ b/block/bfq-cgroup.c
@@ -516,12 +516,13 @@ struct bfq_group *bfq_find_set_group(struct bfq_data *bfqd,
entity = &bfqg->entity;
for_each_entity(entity) {
- bfqg = container_of(entity, struct bfq_group, entity);
- if (bfqg != bfqd->root_group) {
- parent = bfqg_parent(bfqg);
+ struct bfq_group *curr_bfqg = container_of(entity,
+ struct bfq_group, entity);
+ if (curr_bfqg != bfqd->root_group) {
+ parent = bfqg_parent(curr_bfqg);
if (!parent)
parent = bfqd->root_group;
- bfq_group_set_parent(bfqg, parent);
+ bfq_group_set_parent(curr_bfqg, parent);