]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - block/bfq-iosched.c
block, bfq: add/remove entity weights correctly
[linux.git] / block / bfq-iosched.c
index 495b9ddb3355c4637b0bb7668233d73073371420..3f32e88c7e9b37d1e2ea7749ba4d828130151dee 100644 (file)
@@ -742,8 +742,9 @@ void bfq_weights_tree_add(struct bfq_data *bfqd, struct bfq_entity *entity,
  * See the comments to the function bfq_weights_tree_add() for considerations
  * about overhead.
  */
-void bfq_weights_tree_remove(struct bfq_data *bfqd, struct bfq_entity *entity,
-                            struct rb_root *root)
+void __bfq_weights_tree_remove(struct bfq_data *bfqd,
+                              struct bfq_entity *entity,
+                              struct rb_root *root)
 {
        if (!entity->weight_counter)
                return;
@@ -759,6 +760,43 @@ void bfq_weights_tree_remove(struct bfq_data *bfqd, struct bfq_entity *entity,
        entity->weight_counter = NULL;
 }
 
+/*
+ * Invoke __bfq_weights_tree_remove on bfqq and all its inactive
+ * parent entities.
+ */
+void bfq_weights_tree_remove(struct bfq_data *bfqd,
+                            struct bfq_queue *bfqq)
+{
+       struct bfq_entity *entity = bfqq->entity.parent;
+
+       __bfq_weights_tree_remove(bfqd, &bfqq->entity,
+                                 &bfqd->queue_weights_tree);
+
+       for_each_entity(entity) {
+               struct bfq_sched_data *sd = entity->my_sched_data;
+
+               if (sd->next_in_service || sd->in_service_entity) {
+                       /*
+                        * entity is still active, because either
+                        * next_in_service or in_service_entity is not
+                        * NULL (see the comments on the definition of
+                        * next_in_service for details on why
+                        * in_service_entity must be checked too).
+                        *
+                        * As a consequence, the weight of entity is
+                        * not to be removed. In addition, if entity
+                        * is active, then its parent entities are
+                        * active as well, and thus their weights are
+                        * not to be removed either. In the end, this
+                        * loop must stop here.
+                        */
+                       break;
+               }
+               __bfq_weights_tree_remove(bfqd, entity,
+                                         &bfqd->group_weights_tree);
+       }
+}
+
 /*
  * Return expired entry, or NULL to just start from scratch in rbtree.
  */
@@ -4582,8 +4620,7 @@ static void bfq_completed_request(struct bfq_queue *bfqq, struct bfq_data *bfqd)
                 */
                bfqq->budget_timeout = jiffies;
 
-               bfq_weights_tree_remove(bfqd, &bfqq->entity,
-                                       &bfqd->queue_weights_tree);
+               bfq_weights_tree_remove(bfqd, bfqq);
        }
 
        now_ns = ktime_get_ns();