aboutsummaryrefslogtreecommitdiffstats
path: root/block/blk-cgroup.c
diff options
context:
space:
mode:
authorVivek Goyal <vgoyal@redhat.com>2011-05-19 15:38:28 -0400
committerJens Axboe <jaxboe@fusionio.com>2011-05-20 14:34:52 -0400
commit5624a4e445e2ec27582984b068d7bf7f127cee10 (patch)
tree0827c83c6e5f5fa83bd0dadc1bc395c0f0657dae /block/blk-cgroup.c
parent4843c69d496a8d2e4caab6182fe016b9a79136e0 (diff)
blk-throttle: Make dispatch stats per cpu
Currently we take blkg_stat lock for even updating the stats. So even if a group has no throttling rules (common case for root group), we end up taking blkg_lock, for updating the stats. Make dispatch stats per cpu so that these can be updated without taking blkg lock. If cpu goes offline, these stats simply disappear. No protection has been provided for that yet. Do we really need anything for that? Signed-off-by: Vivek Goyal <vgoyal@redhat.com> Signed-off-by: Jens Axboe <jaxboe@fusionio.com>
Diffstat (limited to 'block/blk-cgroup.c')
-rw-r--r--block/blk-cgroup.c135
1 files changed, 100 insertions, 35 deletions
diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c
index b0592bca6970..34bfcefdd924 100644
--- a/block/blk-cgroup.c
+++ b/block/blk-cgroup.c
@@ -392,20 +392,22 @@ void blkiocg_update_timeslice_used(struct blkio_group *blkg, unsigned long time,
392} 392}
393EXPORT_SYMBOL_GPL(blkiocg_update_timeslice_used); 393EXPORT_SYMBOL_GPL(blkiocg_update_timeslice_used);
394 394
395/*
396 * should be called under rcu read lock or queue lock to make sure blkg pointer
397 * is valid.
398 */
395void blkiocg_update_dispatch_stats(struct blkio_group *blkg, 399void blkiocg_update_dispatch_stats(struct blkio_group *blkg,
396 uint64_t bytes, bool direction, bool sync) 400 uint64_t bytes, bool direction, bool sync)
397{ 401{
398 struct blkio_group_stats *stats; 402 struct blkio_group_stats_cpu *stats_cpu;
399 unsigned long flags;
400 403
401 spin_lock_irqsave(&blkg->stats_lock, flags); 404 stats_cpu = this_cpu_ptr(blkg->stats_cpu);
402 stats = &blkg->stats; 405
403 stats->sectors += bytes >> 9; 406 stats_cpu->sectors += bytes >> 9;
404 blkio_add_stat(stats->stat_arr[BLKIO_STAT_SERVICED], 1, direction, 407 blkio_add_stat(stats_cpu->stat_arr_cpu[BLKIO_STAT_CPU_SERVICED],
405 sync); 408 1, direction, sync);
406 blkio_add_stat(stats->stat_arr[BLKIO_STAT_SERVICE_BYTES], bytes, 409 blkio_add_stat(stats_cpu->stat_arr_cpu[BLKIO_STAT_CPU_SERVICE_BYTES],
407 direction, sync); 410 bytes, direction, sync);
408 spin_unlock_irqrestore(&blkg->stats_lock, flags);
409} 411}
410EXPORT_SYMBOL_GPL(blkiocg_update_dispatch_stats); 412EXPORT_SYMBOL_GPL(blkiocg_update_dispatch_stats);
411 413
@@ -440,6 +442,20 @@ void blkiocg_update_io_merged_stats(struct blkio_group *blkg, bool direction,
440} 442}
441EXPORT_SYMBOL_GPL(blkiocg_update_io_merged_stats); 443EXPORT_SYMBOL_GPL(blkiocg_update_io_merged_stats);
442 444
445/*
446 * This function allocates the per cpu stats for blkio_group. Should be called
447 * from sleepable context as alloc_per_cpu() requires that.
448 */
449int blkio_alloc_blkg_stats(struct blkio_group *blkg)
450{
451 /* Allocate memory for per cpu stats */
452 blkg->stats_cpu = alloc_percpu(struct blkio_group_stats_cpu);
453 if (!blkg->stats_cpu)
454 return -ENOMEM;
455 return 0;
456}
457EXPORT_SYMBOL_GPL(blkio_alloc_blkg_stats);
458
443void blkiocg_add_blkio_group(struct blkio_cgroup *blkcg, 459void blkiocg_add_blkio_group(struct blkio_cgroup *blkcg,
444 struct blkio_group *blkg, void *key, dev_t dev, 460 struct blkio_group *blkg, void *key, dev_t dev,
445 enum blkio_policy_id plid) 461 enum blkio_policy_id plid)
@@ -600,6 +616,53 @@ static uint64_t blkio_fill_stat(char *str, int chars_left, uint64_t val,
600 return val; 616 return val;
601} 617}
602 618
619
620static uint64_t blkio_read_stat_cpu(struct blkio_group *blkg,
621 enum stat_type_cpu type, enum stat_sub_type sub_type)
622{
623 int cpu;
624 struct blkio_group_stats_cpu *stats_cpu;
625 uint64_t val = 0;
626
627 for_each_possible_cpu(cpu) {
628 stats_cpu = per_cpu_ptr(blkg->stats_cpu, cpu);
629
630 if (type == BLKIO_STAT_CPU_SECTORS)
631 val += stats_cpu->sectors;
632 else
633 val += stats_cpu->stat_arr_cpu[type][sub_type];
634 }
635
636 return val;
637}
638
639static uint64_t blkio_get_stat_cpu(struct blkio_group *blkg,
640 struct cgroup_map_cb *cb, dev_t dev, enum stat_type_cpu type)
641{
642 uint64_t disk_total, val;
643 char key_str[MAX_KEY_LEN];
644 enum stat_sub_type sub_type;
645
646 if (type == BLKIO_STAT_CPU_SECTORS) {
647 val = blkio_read_stat_cpu(blkg, type, 0);
648 return blkio_fill_stat(key_str, MAX_KEY_LEN - 1, val, cb, dev);
649 }
650
651 for (sub_type = BLKIO_STAT_READ; sub_type < BLKIO_STAT_TOTAL;
652 sub_type++) {
653 blkio_get_key_name(sub_type, dev, key_str, MAX_KEY_LEN, false);
654 val = blkio_read_stat_cpu(blkg, type, sub_type);
655 cb->fill(cb, key_str, val);
656 }
657
658 disk_total = blkio_read_stat_cpu(blkg, type, BLKIO_STAT_READ) +
659 blkio_read_stat_cpu(blkg, type, BLKIO_STAT_WRITE);
660
661 blkio_get_key_name(BLKIO_STAT_TOTAL, dev, key_str, MAX_KEY_LEN, false);
662 cb->fill(cb, key_str, disk_total);
663 return disk_total;
664}
665
603/* This should be called with blkg->stats_lock held */ 666/* This should be called with blkg->stats_lock held */
604static uint64_t blkio_get_stat(struct blkio_group *blkg, 667static uint64_t blkio_get_stat(struct blkio_group *blkg,
605 struct cgroup_map_cb *cb, dev_t dev, enum stat_type type) 668 struct cgroup_map_cb *cb, dev_t dev, enum stat_type type)
@@ -611,9 +674,6 @@ static uint64_t blkio_get_stat(struct blkio_group *blkg,
611 if (type == BLKIO_STAT_TIME) 674 if (type == BLKIO_STAT_TIME)
612 return blkio_fill_stat(key_str, MAX_KEY_LEN - 1, 675 return blkio_fill_stat(key_str, MAX_KEY_LEN - 1,
613 blkg->stats.time, cb, dev); 676 blkg->stats.time, cb, dev);
614 if (type == BLKIO_STAT_SECTORS)
615 return blkio_fill_stat(key_str, MAX_KEY_LEN - 1,
616 blkg->stats.sectors, cb, dev);
617#ifdef CONFIG_DEBUG_BLK_CGROUP 677#ifdef CONFIG_DEBUG_BLK_CGROUP
618 if (type == BLKIO_STAT_UNACCOUNTED_TIME) 678 if (type == BLKIO_STAT_UNACCOUNTED_TIME)
619 return blkio_fill_stat(key_str, MAX_KEY_LEN - 1, 679 return blkio_fill_stat(key_str, MAX_KEY_LEN - 1,
@@ -1077,8 +1137,8 @@ static int blkiocg_file_read(struct cgroup *cgrp, struct cftype *cft,
1077} 1137}
1078 1138
1079static int blkio_read_blkg_stats(struct blkio_cgroup *blkcg, 1139static int blkio_read_blkg_stats(struct blkio_cgroup *blkcg,
1080 struct cftype *cft, struct cgroup_map_cb *cb, enum stat_type type, 1140 struct cftype *cft, struct cgroup_map_cb *cb,
1081 bool show_total) 1141 enum stat_type type, bool show_total, bool pcpu)
1082{ 1142{
1083 struct blkio_group *blkg; 1143 struct blkio_group *blkg;
1084 struct hlist_node *n; 1144 struct hlist_node *n;
@@ -1089,10 +1149,15 @@ static int blkio_read_blkg_stats(struct blkio_cgroup *blkcg,
1089 if (blkg->dev) { 1149 if (blkg->dev) {
1090 if (!cftype_blkg_same_policy(cft, blkg)) 1150 if (!cftype_blkg_same_policy(cft, blkg))
1091 continue; 1151 continue;
1092 spin_lock_irq(&blkg->stats_lock); 1152 if (pcpu)
1093 cgroup_total += blkio_get_stat(blkg, cb, blkg->dev, 1153 cgroup_total += blkio_get_stat_cpu(blkg, cb,
1094 type); 1154 blkg->dev, type);
1095 spin_unlock_irq(&blkg->stats_lock); 1155 else {
1156 spin_lock_irq(&blkg->stats_lock);
1157 cgroup_total += blkio_get_stat(blkg, cb,
1158 blkg->dev, type);
1159 spin_unlock_irq(&blkg->stats_lock);
1160 }
1096 } 1161 }
1097 } 1162 }
1098 if (show_total) 1163 if (show_total)
@@ -1116,47 +1181,47 @@ static int blkiocg_file_read_map(struct cgroup *cgrp, struct cftype *cft,
1116 switch(name) { 1181 switch(name) {
1117 case BLKIO_PROP_time: 1182 case BLKIO_PROP_time:
1118 return blkio_read_blkg_stats(blkcg, cft, cb, 1183 return blkio_read_blkg_stats(blkcg, cft, cb,
1119 BLKIO_STAT_TIME, 0); 1184 BLKIO_STAT_TIME, 0, 0);
1120 case BLKIO_PROP_sectors: 1185 case BLKIO_PROP_sectors:
1121 return blkio_read_blkg_stats(blkcg, cft, cb, 1186 return blkio_read_blkg_stats(blkcg, cft, cb,
1122 BLKIO_STAT_SECTORS, 0); 1187 BLKIO_STAT_CPU_SECTORS, 0, 1);
1123 case BLKIO_PROP_io_service_bytes: 1188 case BLKIO_PROP_io_service_bytes:
1124 return blkio_read_blkg_stats(blkcg, cft, cb, 1189 return blkio_read_blkg_stats(blkcg, cft, cb,
1125 BLKIO_STAT_SERVICE_BYTES, 1); 1190 BLKIO_STAT_CPU_SERVICE_BYTES, 1, 1);
1126 case BLKIO_PROP_io_serviced: 1191 case BLKIO_PROP_io_serviced:
1127 return blkio_read_blkg_stats(blkcg, cft, cb, 1192 return blkio_read_blkg_stats(blkcg, cft, cb,
1128 BLKIO_STAT_SERVICED, 1); 1193 BLKIO_STAT_CPU_SERVICED, 1, 1);
1129 case BLKIO_PROP_io_service_time: 1194 case BLKIO_PROP_io_service_time:
1130 return blkio_read_blkg_stats(blkcg, cft, cb, 1195 return blkio_read_blkg_stats(blkcg, cft, cb,
1131 BLKIO_STAT_SERVICE_TIME, 1); 1196 BLKIO_STAT_SERVICE_TIME, 1, 0);
1132 case BLKIO_PROP_io_wait_time: 1197 case BLKIO_PROP_io_wait_time:
1133 return blkio_read_blkg_stats(blkcg, cft, cb, 1198 return blkio_read_blkg_stats(blkcg, cft, cb,
1134 BLKIO_STAT_WAIT_TIME, 1); 1199 BLKIO_STAT_WAIT_TIME, 1, 0);
1135 case BLKIO_PROP_io_merged: 1200 case BLKIO_PROP_io_merged:
1136 return blkio_read_blkg_stats(blkcg, cft, cb, 1201 return blkio_read_blkg_stats(blkcg, cft, cb,
1137 BLKIO_STAT_MERGED, 1); 1202 BLKIO_STAT_MERGED, 1, 0);
1138 case BLKIO_PROP_io_queued: 1203 case BLKIO_PROP_io_queued:
1139 return blkio_read_blkg_stats(blkcg, cft, cb, 1204 return blkio_read_blkg_stats(blkcg, cft, cb,
1140 BLKIO_STAT_QUEUED, 1); 1205 BLKIO_STAT_QUEUED, 1, 0);
1141#ifdef CONFIG_DEBUG_BLK_CGROUP 1206#ifdef CONFIG_DEBUG_BLK_CGROUP
1142 case BLKIO_PROP_unaccounted_time: 1207 case BLKIO_PROP_unaccounted_time:
1143 return blkio_read_blkg_stats(blkcg, cft, cb, 1208 return blkio_read_blkg_stats(blkcg, cft, cb,
1144 BLKIO_STAT_UNACCOUNTED_TIME, 0); 1209 BLKIO_STAT_UNACCOUNTED_TIME, 0, 0);
1145 case BLKIO_PROP_dequeue: 1210 case BLKIO_PROP_dequeue:
1146 return blkio_read_blkg_stats(blkcg, cft, cb, 1211 return blkio_read_blkg_stats(blkcg, cft, cb,
1147 BLKIO_STAT_DEQUEUE, 0); 1212 BLKIO_STAT_DEQUEUE, 0, 0);
1148 case BLKIO_PROP_avg_queue_size: 1213 case BLKIO_PROP_avg_queue_size:
1149 return blkio_read_blkg_stats(blkcg, cft, cb, 1214 return blkio_read_blkg_stats(blkcg, cft, cb,
1150 BLKIO_STAT_AVG_QUEUE_SIZE, 0); 1215 BLKIO_STAT_AVG_QUEUE_SIZE, 0, 0);
1151 case BLKIO_PROP_group_wait_time: 1216 case BLKIO_PROP_group_wait_time:
1152 return blkio_read_blkg_stats(blkcg, cft, cb, 1217 return blkio_read_blkg_stats(blkcg, cft, cb,
1153 BLKIO_STAT_GROUP_WAIT_TIME, 0); 1218 BLKIO_STAT_GROUP_WAIT_TIME, 0, 0);
1154 case BLKIO_PROP_idle_time: 1219 case BLKIO_PROP_idle_time:
1155 return blkio_read_blkg_stats(blkcg, cft, cb, 1220 return blkio_read_blkg_stats(blkcg, cft, cb,
1156 BLKIO_STAT_IDLE_TIME, 0); 1221 BLKIO_STAT_IDLE_TIME, 0, 0);
1157 case BLKIO_PROP_empty_time: 1222 case BLKIO_PROP_empty_time:
1158 return blkio_read_blkg_stats(blkcg, cft, cb, 1223 return blkio_read_blkg_stats(blkcg, cft, cb,
1159 BLKIO_STAT_EMPTY_TIME, 0); 1224 BLKIO_STAT_EMPTY_TIME, 0, 0);
1160#endif 1225#endif
1161 default: 1226 default:
1162 BUG(); 1227 BUG();
@@ -1166,10 +1231,10 @@ static int blkiocg_file_read_map(struct cgroup *cgrp, struct cftype *cft,
1166 switch(name){ 1231 switch(name){
1167 case BLKIO_THROTL_io_service_bytes: 1232 case BLKIO_THROTL_io_service_bytes:
1168 return blkio_read_blkg_stats(blkcg, cft, cb, 1233 return blkio_read_blkg_stats(blkcg, cft, cb,
1169 BLKIO_STAT_SERVICE_BYTES, 1); 1234 BLKIO_STAT_CPU_SERVICE_BYTES, 1, 1);
1170 case BLKIO_THROTL_io_serviced: 1235 case BLKIO_THROTL_io_serviced:
1171 return blkio_read_blkg_stats(blkcg, cft, cb, 1236 return blkio_read_blkg_stats(blkcg, cft, cb,
1172 BLKIO_STAT_SERVICED, 1); 1237 BLKIO_STAT_CPU_SERVICED, 1, 1);
1173 default: 1238 default:
1174 BUG(); 1239 BUG();
1175 } 1240 }