block, bfq: get a ref to a group when adding it to a service tree
authorPaolo Valente <paolo.valente@linaro.org>
Mon, 3 Feb 2020 10:40:59 +0000 (11:40 +0100)
committerJens Axboe <axboe@kernel.dk>
Mon, 3 Feb 2020 13:58:15 +0000 (06:58 -0700)
BFQ schedules generic entities, which may represent either bfq_queues
or groups of bfq_queues. When an entity is inserted into a service
tree, a reference must be taken, to make sure that the entity does not
disappear while still referred in the tree. Unfortunately, such a
reference is mistakenly taken only if the entity represents a
bfq_queue. This commit takes a reference also in case the entity
represents a group.

Tested-by: Oleksandr Natalenko <oleksandr@natalenko.name>
Tested-by: Chris Evich <cevich@redhat.com>
Signed-off-by: Paolo Valente <paolo.valente@linaro.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
block/bfq-cgroup.c
block/bfq-iosched.h
block/bfq-wf2q.c

index cae488b58049cf7297db85c6249524dbd030cca1..09b69a3ed490362a13ff290b5d46ee1b477277ad 100644 (file)
@@ -332,7 +332,7 @@ static void bfqg_put(struct bfq_group *bfqg)
                kfree(bfqg);
 }
 
-static void bfqg_and_blkg_get(struct bfq_group *bfqg)
+void bfqg_and_blkg_get(struct bfq_group *bfqg)
 {
        /* see comments in bfq_bic_update_cgroup for why refcounting bfqg */
        bfqg_get(bfqg);
index 2c7cec737b2aeb7f2f2039edd81a3221ef3d4d5a..d1233af9c6844d0578ed8f8a29ef37d63e244aaf 100644 (file)
@@ -985,6 +985,7 @@ struct bfq_group *bfq_find_set_group(struct bfq_data *bfqd,
 struct blkcg_gq *bfqg_to_blkg(struct bfq_group *bfqg);
 struct bfq_group *bfqq_group(struct bfq_queue *bfqq);
 struct bfq_group *bfq_create_group_hierarchy(struct bfq_data *bfqd, int node);
+void bfqg_and_blkg_get(struct bfq_group *bfqg);
 void bfqg_and_blkg_put(struct bfq_group *bfqg);
 
 #ifdef CONFIG_BFQ_GROUP_IOSCHED
index 26776bdbdf360c97635c6fb197b0b3c497689f2e..eb0e2a6daabe63f30be59394f73e201e05f59488 100644 (file)
@@ -533,7 +533,9 @@ static void bfq_get_entity(struct bfq_entity *entity)
                bfqq->ref++;
                bfq_log_bfqq(bfqq->bfqd, bfqq, "get_entity: %p %d",
                             bfqq, bfqq->ref);
-       }
+       } else
+               bfqg_and_blkg_get(container_of(entity, struct bfq_group,
+                                              entity));
 }
 
 /**
@@ -647,8 +649,14 @@ static void bfq_forget_entity(struct bfq_service_tree *st,
 
        entity->on_st_or_in_serv = false;
        st->wsum -= entity->weight;
-       if (bfqq && !is_in_service)
+       if (is_in_service)
+               return;
+
+       if (bfqq)
                bfq_put_queue(bfqq);
+       else
+               bfqg_and_blkg_put(container_of(entity, struct bfq_group,
+                                              entity));
 }
 
 /**