aboutsummaryrefslogtreecommitdiffstats
path: root/block/cfq-iosched.c
diff options
context:
space:
mode:
authorJustin TerAvest <teravest@google.com>2011-03-17 11:12:36 -0400
committerJens Axboe <jaxboe@fusionio.com>2011-03-17 11:12:36 -0400
commit8184f93eced1e304721c2a55c00d87d5a14f8907 (patch)
treeb5ed43533eee883bc25920c191cb095584d29822 /block/cfq-iosched.c
parent95f28604a65b1c40b6c6cd95e58439cd7ded3add (diff)
cfq-iosched: Don't update group weights when on service tree
Version 3 is updated to apply to for-2.6.39/core. For version 2, I took Vivek's advice and made sure we update the group weight from cfq_group_service_tree_add(). If a weight was updated while a group is on the service tree, the calculation for the total weight of the service tree can be adjusted improperly, which either leads to bad service tree weights, or potentially crashes (if total_weight becomes 0). This patch defers updates to the weight until a group is off the service tree. Signed-off-by: Justin TerAvest <teravest@google.com> Acked-by: Vivek Goyal <vgoyal@redhat.com> Signed-off-by: Jens Axboe <jaxboe@fusionio.com>
Diffstat (limited to 'block/cfq-iosched.c')
-rw-r--r--block/cfq-iosched.c53
1 files changed, 41 insertions, 12 deletions
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c
index 89e0d1cc14ba..12e380b2c4e4 100644
--- a/block/cfq-iosched.c
+++ b/block/cfq-iosched.c
@@ -178,6 +178,8 @@ struct cfq_group {
178 /* group service_tree key */ 178 /* group service_tree key */
179 u64 vdisktime; 179 u64 vdisktime;
180 unsigned int weight; 180 unsigned int weight;
181 unsigned int new_weight;
182 bool needs_update;
181 183
182 /* number of cfqq currently on this group */ 184 /* number of cfqq currently on this group */
183 int nr_cfqq; 185 int nr_cfqq;
@@ -853,7 +855,27 @@ __cfq_group_service_tree_add(struct cfq_rb_root *st, struct cfq_group *cfqg)
853} 855}
854 856
855static void 857static void
856cfq_group_service_tree_add(struct cfq_data *cfqd, struct cfq_group *cfqg) 858cfq_update_group_weight(struct cfq_group *cfqg)
859{
860 BUG_ON(!RB_EMPTY_NODE(&cfqg->rb_node));
861 if (cfqg->needs_update) {
862 cfqg->weight = cfqg->new_weight;
863 cfqg->needs_update = false;
864 }
865}
866
867static void
868cfq_group_service_tree_add(struct cfq_rb_root *st, struct cfq_group *cfqg)
869{
870 BUG_ON(!RB_EMPTY_NODE(&cfqg->rb_node));
871
872 cfq_update_group_weight(cfqg);
873 __cfq_group_service_tree_add(st, cfqg);
874 st->total_weight += cfqg->weight;
875}
876
877static void
878cfq_group_notify_queue_add(struct cfq_data *cfqd, struct cfq_group *cfqg)
857{ 879{
858 struct cfq_rb_root *st = &cfqd->grp_service_tree; 880 struct cfq_rb_root *st = &cfqd->grp_service_tree;
859 struct cfq_group *__cfqg; 881 struct cfq_group *__cfqg;
@@ -874,13 +896,19 @@ cfq_group_service_tree_add(struct cfq_data *cfqd, struct cfq_group *cfqg)
874 cfqg->vdisktime = __cfqg->vdisktime + CFQ_IDLE_DELAY; 896 cfqg->vdisktime = __cfqg->vdisktime + CFQ_IDLE_DELAY;
875 } else 897 } else
876 cfqg->vdisktime = st->min_vdisktime; 898 cfqg->vdisktime = st->min_vdisktime;
899 cfq_group_service_tree_add(st, cfqg);
900}
877 901
878 __cfq_group_service_tree_add(st, cfqg); 902static void
879 st->total_weight += cfqg->weight; 903cfq_group_service_tree_del(struct cfq_rb_root *st, struct cfq_group *cfqg)
904{
905 st->total_weight -= cfqg->weight;
906 if (!RB_EMPTY_NODE(&cfqg->rb_node))
907 cfq_rb_erase(&cfqg->rb_node, st);
880} 908}
881 909
882static void 910static void
883cfq_group_service_tree_del(struct cfq_data *cfqd, struct cfq_group *cfqg) 911cfq_group_notify_queue_del(struct cfq_data *cfqd, struct cfq_group *cfqg)
884{ 912{
885 struct cfq_rb_root *st = &cfqd->grp_service_tree; 913 struct cfq_rb_root *st = &cfqd->grp_service_tree;
886 914
@@ -892,9 +920,7 @@ cfq_group_service_tree_del(struct cfq_data *cfqd, struct cfq_group *cfqg)
892 return; 920 return;
893 921
894 cfq_log_cfqg(cfqd, cfqg, "del_from_rr group"); 922 cfq_log_cfqg(cfqd, cfqg, "del_from_rr group");
895 st->total_weight -= cfqg->weight; 923 cfq_group_service_tree_del(st, cfqg);
896 if (!RB_EMPTY_NODE(&cfqg->rb_node))
897 cfq_rb_erase(&cfqg->rb_node, st);
898 cfqg->saved_workload_slice = 0; 924 cfqg->saved_workload_slice = 0;
899 cfq_blkiocg_update_dequeue_stats(&cfqg->blkg, 1); 925 cfq_blkiocg_update_dequeue_stats(&cfqg->blkg, 1);
900} 926}
@@ -948,9 +974,10 @@ static void cfq_group_served(struct cfq_data *cfqd, struct cfq_group *cfqg,
948 charge = cfqq->allocated_slice; 974 charge = cfqq->allocated_slice;
949 975
950 /* Can't update vdisktime while group is on service tree */ 976 /* Can't update vdisktime while group is on service tree */
951 cfq_rb_erase(&cfqg->rb_node, st); 977 cfq_group_service_tree_del(st, cfqg);
952 cfqg->vdisktime += cfq_scale_slice(charge, cfqg); 978 cfqg->vdisktime += cfq_scale_slice(charge, cfqg);
953 __cfq_group_service_tree_add(st, cfqg); 979 /* If a new weight was requested, update now, off tree */
980 cfq_group_service_tree_add(st, cfqg);
954 981
955 /* This group is being expired. Save the context */ 982 /* This group is being expired. Save the context */
956 if (time_after(cfqd->workload_expires, jiffies)) { 983 if (time_after(cfqd->workload_expires, jiffies)) {
@@ -982,7 +1009,9 @@ static inline struct cfq_group *cfqg_of_blkg(struct blkio_group *blkg)
982void cfq_update_blkio_group_weight(void *key, struct blkio_group *blkg, 1009void cfq_update_blkio_group_weight(void *key, struct blkio_group *blkg,
983 unsigned int weight) 1010 unsigned int weight)
984{ 1011{
985 cfqg_of_blkg(blkg)->weight = weight; 1012 struct cfq_group *cfqg = cfqg_of_blkg(blkg);
1013 cfqg->new_weight = weight;
1014 cfqg->needs_update = true;
986} 1015}
987 1016
988static struct cfq_group * 1017static struct cfq_group *
@@ -1255,7 +1284,7 @@ static void cfq_service_tree_add(struct cfq_data *cfqd, struct cfq_queue *cfqq,
1255 service_tree->count++; 1284 service_tree->count++;
1256 if ((add_front || !new_cfqq) && !group_changed) 1285 if ((add_front || !new_cfqq) && !group_changed)
1257 return; 1286 return;
1258 cfq_group_service_tree_add(cfqd, cfqq->cfqg); 1287 cfq_group_notify_queue_add(cfqd, cfqq->cfqg);
1259} 1288}
1260 1289
1261static struct cfq_queue * 1290static struct cfq_queue *
@@ -1368,7 +1397,7 @@ static void cfq_del_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq)
1368 cfqq->p_root = NULL; 1397 cfqq->p_root = NULL;
1369 } 1398 }
1370 1399
1371 cfq_group_service_tree_del(cfqd, cfqq->cfqg); 1400 cfq_group_notify_queue_del(cfqd, cfqq->cfqg);
1372 BUG_ON(!cfqd->busy_queues); 1401 BUG_ON(!cfqd->busy_queues);
1373 cfqd->busy_queues--; 1402 cfqd->busy_queues--;
1374 if (cfq_cfqq_sync(cfqq)) 1403 if (cfq_cfqq_sync(cfqq))