|
@@ -178,6 +178,8 @@ struct cfq_group {
|
|
/* group service_tree key */
|
|
/* group service_tree key */
|
|
u64 vdisktime;
|
|
u64 vdisktime;
|
|
unsigned int weight;
|
|
unsigned int weight;
|
|
|
|
+ unsigned int new_weight;
|
|
|
|
+ bool needs_update;
|
|
|
|
|
|
/* number of cfqq currently on this group */
|
|
/* number of cfqq currently on this group */
|
|
int nr_cfqq;
|
|
int nr_cfqq;
|
|
@@ -853,7 +855,27 @@ __cfq_group_service_tree_add(struct cfq_rb_root *st, struct cfq_group *cfqg)
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
static void
|
|
-cfq_group_service_tree_add(struct cfq_data *cfqd, struct cfq_group *cfqg)
|
|
|
|
|
|
+cfq_update_group_weight(struct cfq_group *cfqg)
|
|
|
|
+{
|
|
|
|
+ BUG_ON(!RB_EMPTY_NODE(&cfqg->rb_node));
|
|
|
|
+ if (cfqg->needs_update) {
|
|
|
|
+ cfqg->weight = cfqg->new_weight;
|
|
|
|
+ cfqg->needs_update = false;
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void
|
|
|
|
+cfq_group_service_tree_add(struct cfq_rb_root *st, struct cfq_group *cfqg)
|
|
|
|
+{
|
|
|
|
+ BUG_ON(!RB_EMPTY_NODE(&cfqg->rb_node));
|
|
|
|
+
|
|
|
|
+ cfq_update_group_weight(cfqg);
|
|
|
|
+ __cfq_group_service_tree_add(st, cfqg);
|
|
|
|
+ st->total_weight += cfqg->weight;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void
|
|
|
|
+cfq_group_notify_queue_add(struct cfq_data *cfqd, struct cfq_group *cfqg)
|
|
{
|
|
{
|
|
struct cfq_rb_root *st = &cfqd->grp_service_tree;
|
|
struct cfq_rb_root *st = &cfqd->grp_service_tree;
|
|
struct cfq_group *__cfqg;
|
|
struct cfq_group *__cfqg;
|
|
@@ -874,13 +896,19 @@ cfq_group_service_tree_add(struct cfq_data *cfqd, struct cfq_group *cfqg)
|
|
cfqg->vdisktime = __cfqg->vdisktime + CFQ_IDLE_DELAY;
|
|
cfqg->vdisktime = __cfqg->vdisktime + CFQ_IDLE_DELAY;
|
|
} else
|
|
} else
|
|
cfqg->vdisktime = st->min_vdisktime;
|
|
cfqg->vdisktime = st->min_vdisktime;
|
|
|
|
+ cfq_group_service_tree_add(st, cfqg);
|
|
|
|
+}
|
|
|
|
|
|
- __cfq_group_service_tree_add(st, cfqg);
|
|
|
|
- st->total_weight += cfqg->weight;
|
|
|
|
|
|
+static void
|
|
|
|
+cfq_group_service_tree_del(struct cfq_rb_root *st, struct cfq_group *cfqg)
|
|
|
|
+{
|
|
|
|
+ st->total_weight -= cfqg->weight;
|
|
|
|
+ if (!RB_EMPTY_NODE(&cfqg->rb_node))
|
|
|
|
+ cfq_rb_erase(&cfqg->rb_node, st);
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
static void
|
|
-cfq_group_service_tree_del(struct cfq_data *cfqd, struct cfq_group *cfqg)
|
|
|
|
|
|
+cfq_group_notify_queue_del(struct cfq_data *cfqd, struct cfq_group *cfqg)
|
|
{
|
|
{
|
|
struct cfq_rb_root *st = &cfqd->grp_service_tree;
|
|
struct cfq_rb_root *st = &cfqd->grp_service_tree;
|
|
|
|
|
|
@@ -892,9 +920,7 @@ cfq_group_service_tree_del(struct cfq_data *cfqd, struct cfq_group *cfqg)
|
|
return;
|
|
return;
|
|
|
|
|
|
cfq_log_cfqg(cfqd, cfqg, "del_from_rr group");
|
|
cfq_log_cfqg(cfqd, cfqg, "del_from_rr group");
|
|
- st->total_weight -= cfqg->weight;
|
|
|
|
- if (!RB_EMPTY_NODE(&cfqg->rb_node))
|
|
|
|
- cfq_rb_erase(&cfqg->rb_node, st);
|
|
|
|
|
|
+ cfq_group_service_tree_del(st, cfqg);
|
|
cfqg->saved_workload_slice = 0;
|
|
cfqg->saved_workload_slice = 0;
|
|
cfq_blkiocg_update_dequeue_stats(&cfqg->blkg, 1);
|
|
cfq_blkiocg_update_dequeue_stats(&cfqg->blkg, 1);
|
|
}
|
|
}
|
|
@@ -948,9 +974,10 @@ static void cfq_group_served(struct cfq_data *cfqd, struct cfq_group *cfqg,
|
|
charge = cfqq->allocated_slice;
|
|
charge = cfqq->allocated_slice;
|
|
|
|
|
|
/* Can't update vdisktime while group is on service tree */
|
|
/* Can't update vdisktime while group is on service tree */
|
|
- cfq_rb_erase(&cfqg->rb_node, st);
|
|
|
|
|
|
+ cfq_group_service_tree_del(st, cfqg);
|
|
cfqg->vdisktime += cfq_scale_slice(charge, cfqg);
|
|
cfqg->vdisktime += cfq_scale_slice(charge, cfqg);
|
|
- __cfq_group_service_tree_add(st, cfqg);
|
|
|
|
|
|
+ /* If a new weight was requested, update now, off tree */
|
|
|
|
+ cfq_group_service_tree_add(st, cfqg);
|
|
|
|
|
|
/* This group is being expired. Save the context */
|
|
/* This group is being expired. Save the context */
|
|
if (time_after(cfqd->workload_expires, jiffies)) {
|
|
if (time_after(cfqd->workload_expires, jiffies)) {
|
|
@@ -982,7 +1009,9 @@ static inline struct cfq_group *cfqg_of_blkg(struct blkio_group *blkg)
|
|
void cfq_update_blkio_group_weight(void *key, struct blkio_group *blkg,
|
|
void cfq_update_blkio_group_weight(void *key, struct blkio_group *blkg,
|
|
unsigned int weight)
|
|
unsigned int weight)
|
|
{
|
|
{
|
|
- cfqg_of_blkg(blkg)->weight = weight;
|
|
|
|
|
|
+ struct cfq_group *cfqg = cfqg_of_blkg(blkg);
|
|
|
|
+ cfqg->new_weight = weight;
|
|
|
|
+ cfqg->needs_update = true;
|
|
}
|
|
}
|
|
|
|
|
|
static struct cfq_group *
|
|
static struct cfq_group *
|
|
@@ -1255,7 +1284,7 @@ static void cfq_service_tree_add(struct cfq_data *cfqd, struct cfq_queue *cfqq,
|
|
service_tree->count++;
|
|
service_tree->count++;
|
|
if ((add_front || !new_cfqq) && !group_changed)
|
|
if ((add_front || !new_cfqq) && !group_changed)
|
|
return;
|
|
return;
|
|
- cfq_group_service_tree_add(cfqd, cfqq->cfqg);
|
|
|
|
|
|
+ cfq_group_notify_queue_add(cfqd, cfqq->cfqg);
|
|
}
|
|
}
|
|
|
|
|
|
static struct cfq_queue *
|
|
static struct cfq_queue *
|
|
@@ -1368,7 +1397,7 @@ static void cfq_del_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq)
|
|
cfqq->p_root = NULL;
|
|
cfqq->p_root = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
- cfq_group_service_tree_del(cfqd, cfqq->cfqg);
|
|
|
|
|
|
+ cfq_group_notify_queue_del(cfqd, cfqq->cfqg);
|
|
BUG_ON(!cfqd->busy_queues);
|
|
BUG_ON(!cfqd->busy_queues);
|
|
cfqd->busy_queues--;
|
|
cfqd->busy_queues--;
|
|
if (cfq_cfqq_sync(cfqq))
|
|
if (cfq_cfqq_sync(cfqq))
|