| From 99fec430f7028454bcaa2bef75357cada98e3044 Mon Sep 17 00:00:00 2001 |
| From: Carlo Nonato <carlo.nonato95@gmail.com> |
| Date: Fri, 6 Mar 2020 13:27:31 +0100 |
| Subject: [PATCH] block, bfq: fix overwrite of bfq_group pointer in |
| bfq_find_set_group() |
| |
| 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 <kwonje.oh2@gmail.com> |
| Signed-off-by: Carlo Nonato <carlo.nonato95@gmail.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 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); |
| } |
| } |
| |
| -- |
| 2.7.4 |
| |