diff options
Diffstat (limited to 'block/blk-cgroup.c')
-rw-r--r-- | block/blk-cgroup.c | 190 |
1 files changed, 88 insertions, 102 deletions
diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c index 9af7257f429c..6797df508821 100644 --- a/block/blk-cgroup.c +++ b/block/blk-cgroup.c | |||
@@ -18,6 +18,8 @@ | |||
18 | #include <linux/blkdev.h> | 18 | #include <linux/blkdev.h> |
19 | #include "blk-cgroup.h" | 19 | #include "blk-cgroup.h" |
20 | 20 | ||
21 | #define MAX_KEY_LEN 100 | ||
22 | |||
21 | static DEFINE_SPINLOCK(blkio_list_lock); | 23 | static DEFINE_SPINLOCK(blkio_list_lock); |
22 | static LIST_HEAD(blkio_list); | 24 | static LIST_HEAD(blkio_list); |
23 | 25 | ||
@@ -56,24 +58,27 @@ struct blkio_cgroup *cgroup_to_blkio_cgroup(struct cgroup *cgroup) | |||
56 | } | 58 | } |
57 | EXPORT_SYMBOL_GPL(cgroup_to_blkio_cgroup); | 59 | EXPORT_SYMBOL_GPL(cgroup_to_blkio_cgroup); |
58 | 60 | ||
61 | void blkio_group_init(struct blkio_group *blkg) | ||
62 | { | ||
63 | spin_lock_init(&blkg->stats_lock); | ||
64 | } | ||
65 | EXPORT_SYMBOL_GPL(blkio_group_init); | ||
66 | |||
59 | /* | 67 | /* |
60 | * Add to the appropriate stat variable depending on the request type. | 68 | * Add to the appropriate stat variable depending on the request type. |
61 | * This should be called with the blkg->stats_lock held. | 69 | * This should be called with the blkg->stats_lock held. |
62 | */ | 70 | */ |
63 | void io_add_stat(uint64_t *stat, uint64_t add, unsigned int flags) | 71 | static void blkio_add_stat(uint64_t *stat, uint64_t add, bool direction, |
72 | bool sync) | ||
64 | { | 73 | { |
65 | if (flags & REQ_RW) | 74 | if (direction) |
66 | stat[IO_WRITE] += add; | 75 | stat[BLKIO_STAT_WRITE] += add; |
67 | else | 76 | else |
68 | stat[IO_READ] += add; | 77 | stat[BLKIO_STAT_READ] += add; |
69 | /* | 78 | if (sync) |
70 | * Everywhere in the block layer, an IO is treated as sync if it is a | 79 | stat[BLKIO_STAT_SYNC] += add; |
71 | * read or a SYNC write. We follow the same norm. | ||
72 | */ | ||
73 | if (!(flags & REQ_RW) || flags & REQ_RW_SYNC) | ||
74 | stat[IO_SYNC] += add; | ||
75 | else | 80 | else |
76 | stat[IO_ASYNC] += add; | 81 | stat[BLKIO_STAT_ASYNC] += add; |
77 | } | 82 | } |
78 | 83 | ||
79 | void blkiocg_update_timeslice_used(struct blkio_group *blkg, unsigned long time) | 84 | void blkiocg_update_timeslice_used(struct blkio_group *blkg, unsigned long time) |
@@ -86,23 +91,25 @@ void blkiocg_update_timeslice_used(struct blkio_group *blkg, unsigned long time) | |||
86 | } | 91 | } |
87 | EXPORT_SYMBOL_GPL(blkiocg_update_timeslice_used); | 92 | EXPORT_SYMBOL_GPL(blkiocg_update_timeslice_used); |
88 | 93 | ||
89 | void blkiocg_update_request_dispatch_stats(struct blkio_group *blkg, | 94 | void blkiocg_update_dispatch_stats(struct blkio_group *blkg, |
90 | struct request *rq) | 95 | uint64_t bytes, bool direction, bool sync) |
91 | { | 96 | { |
92 | struct blkio_group_stats *stats; | 97 | struct blkio_group_stats *stats; |
93 | unsigned long flags; | 98 | unsigned long flags; |
94 | 99 | ||
95 | spin_lock_irqsave(&blkg->stats_lock, flags); | 100 | spin_lock_irqsave(&blkg->stats_lock, flags); |
96 | stats = &blkg->stats; | 101 | stats = &blkg->stats; |
97 | stats->sectors += blk_rq_sectors(rq); | 102 | stats->sectors += bytes >> 9; |
98 | io_add_stat(stats->io_serviced, 1, rq->cmd_flags); | 103 | blkio_add_stat(stats->stat_arr[BLKIO_STAT_SERVICED], 1, direction, |
99 | io_add_stat(stats->io_service_bytes, blk_rq_sectors(rq) << 9, | 104 | sync); |
100 | rq->cmd_flags); | 105 | blkio_add_stat(stats->stat_arr[BLKIO_STAT_SERVICE_BYTES], bytes, |
106 | direction, sync); | ||
101 | spin_unlock_irqrestore(&blkg->stats_lock, flags); | 107 | spin_unlock_irqrestore(&blkg->stats_lock, flags); |
102 | } | 108 | } |
109 | EXPORT_SYMBOL_GPL(blkiocg_update_dispatch_stats); | ||
103 | 110 | ||
104 | void blkiocg_update_request_completion_stats(struct blkio_group *blkg, | 111 | void blkiocg_update_completion_stats(struct blkio_group *blkg, |
105 | struct request *rq) | 112 | uint64_t start_time, uint64_t io_start_time, bool direction, bool sync) |
106 | { | 113 | { |
107 | struct blkio_group_stats *stats; | 114 | struct blkio_group_stats *stats; |
108 | unsigned long flags; | 115 | unsigned long flags; |
@@ -110,16 +117,15 @@ void blkiocg_update_request_completion_stats(struct blkio_group *blkg, | |||
110 | 117 | ||
111 | spin_lock_irqsave(&blkg->stats_lock, flags); | 118 | spin_lock_irqsave(&blkg->stats_lock, flags); |
112 | stats = &blkg->stats; | 119 | stats = &blkg->stats; |
113 | if (time_after64(now, rq->io_start_time_ns)) | 120 | if (time_after64(now, io_start_time)) |
114 | io_add_stat(stats->io_service_time, now - rq->io_start_time_ns, | 121 | blkio_add_stat(stats->stat_arr[BLKIO_STAT_SERVICE_TIME], |
115 | rq->cmd_flags); | 122 | now - io_start_time, direction, sync); |
116 | if (time_after64(rq->io_start_time_ns, rq->start_time_ns)) | 123 | if (time_after64(io_start_time, start_time)) |
117 | io_add_stat(stats->io_wait_time, | 124 | blkio_add_stat(stats->stat_arr[BLKIO_STAT_WAIT_TIME], |
118 | rq->io_start_time_ns - rq->start_time_ns, | 125 | io_start_time - start_time, direction, sync); |
119 | rq->cmd_flags); | ||
120 | spin_unlock_irqrestore(&blkg->stats_lock, flags); | 126 | spin_unlock_irqrestore(&blkg->stats_lock, flags); |
121 | } | 127 | } |
122 | EXPORT_SYMBOL_GPL(blkiocg_update_request_completion_stats); | 128 | EXPORT_SYMBOL_GPL(blkiocg_update_completion_stats); |
123 | 129 | ||
124 | void blkiocg_add_blkio_group(struct blkio_cgroup *blkcg, | 130 | void blkiocg_add_blkio_group(struct blkio_cgroup *blkcg, |
125 | struct blkio_group *blkg, void *key, dev_t dev) | 131 | struct blkio_group *blkg, void *key, dev_t dev) |
@@ -230,7 +236,7 @@ blkiocg_weight_write(struct cgroup *cgroup, struct cftype *cftype, u64 val) | |||
230 | } | 236 | } |
231 | 237 | ||
232 | static int | 238 | static int |
233 | blkiocg_reset_write(struct cgroup *cgroup, struct cftype *cftype, u64 val) | 239 | blkiocg_reset_stats(struct cgroup *cgroup, struct cftype *cftype, u64 val) |
234 | { | 240 | { |
235 | struct blkio_cgroup *blkcg; | 241 | struct blkio_cgroup *blkcg; |
236 | struct blkio_group *blkg; | 242 | struct blkio_group *blkg; |
@@ -249,29 +255,32 @@ blkiocg_reset_write(struct cgroup *cgroup, struct cftype *cftype, u64 val) | |||
249 | return 0; | 255 | return 0; |
250 | } | 256 | } |
251 | 257 | ||
252 | void get_key_name(int type, char *disk_id, char *str, int chars_left) | 258 | static void blkio_get_key_name(enum stat_sub_type type, dev_t dev, char *str, |
259 | int chars_left, bool diskname_only) | ||
253 | { | 260 | { |
254 | strlcpy(str, disk_id, chars_left); | 261 | snprintf(str, chars_left, "%d:%d", MAJOR(dev), MINOR(dev)); |
255 | chars_left -= strlen(str); | 262 | chars_left -= strlen(str); |
256 | if (chars_left <= 0) { | 263 | if (chars_left <= 0) { |
257 | printk(KERN_WARNING | 264 | printk(KERN_WARNING |
258 | "Possibly incorrect cgroup stat display format"); | 265 | "Possibly incorrect cgroup stat display format"); |
259 | return; | 266 | return; |
260 | } | 267 | } |
268 | if (diskname_only) | ||
269 | return; | ||
261 | switch (type) { | 270 | switch (type) { |
262 | case IO_READ: | 271 | case BLKIO_STAT_READ: |
263 | strlcat(str, " Read", chars_left); | 272 | strlcat(str, " Read", chars_left); |
264 | break; | 273 | break; |
265 | case IO_WRITE: | 274 | case BLKIO_STAT_WRITE: |
266 | strlcat(str, " Write", chars_left); | 275 | strlcat(str, " Write", chars_left); |
267 | break; | 276 | break; |
268 | case IO_SYNC: | 277 | case BLKIO_STAT_SYNC: |
269 | strlcat(str, " Sync", chars_left); | 278 | strlcat(str, " Sync", chars_left); |
270 | break; | 279 | break; |
271 | case IO_ASYNC: | 280 | case BLKIO_STAT_ASYNC: |
272 | strlcat(str, " Async", chars_left); | 281 | strlcat(str, " Async", chars_left); |
273 | break; | 282 | break; |
274 | case IO_TYPE_MAX: | 283 | case BLKIO_STAT_TOTAL: |
275 | strlcat(str, " Total", chars_left); | 284 | strlcat(str, " Total", chars_left); |
276 | break; | 285 | break; |
277 | default: | 286 | default: |
@@ -279,63 +288,47 @@ void get_key_name(int type, char *disk_id, char *str, int chars_left) | |||
279 | } | 288 | } |
280 | } | 289 | } |
281 | 290 | ||
282 | typedef uint64_t (get_var) (struct blkio_group *, int); | 291 | static uint64_t blkio_fill_stat(char *str, int chars_left, uint64_t val, |
292 | struct cgroup_map_cb *cb, dev_t dev) | ||
293 | { | ||
294 | blkio_get_key_name(0, dev, str, chars_left, true); | ||
295 | cb->fill(cb, str, val); | ||
296 | return val; | ||
297 | } | ||
283 | 298 | ||
284 | #define MAX_KEY_LEN 100 | 299 | /* This should be called with blkg->stats_lock held */ |
285 | uint64_t get_typed_stat(struct blkio_group *blkg, struct cgroup_map_cb *cb, | 300 | static uint64_t blkio_get_stat(struct blkio_group *blkg, |
286 | get_var *getvar, char *disk_id) | 301 | struct cgroup_map_cb *cb, dev_t dev, enum stat_type type) |
287 | { | 302 | { |
288 | uint64_t disk_total; | 303 | uint64_t disk_total; |
289 | char key_str[MAX_KEY_LEN]; | 304 | char key_str[MAX_KEY_LEN]; |
290 | int type; | 305 | enum stat_sub_type sub_type; |
306 | |||
307 | if (type == BLKIO_STAT_TIME) | ||
308 | return blkio_fill_stat(key_str, MAX_KEY_LEN - 1, | ||
309 | blkg->stats.time, cb, dev); | ||
310 | if (type == BLKIO_STAT_SECTORS) | ||
311 | return blkio_fill_stat(key_str, MAX_KEY_LEN - 1, | ||
312 | blkg->stats.sectors, cb, dev); | ||
313 | #ifdef CONFIG_DEBUG_BLK_CGROUP | ||
314 | if (type == BLKIO_STAT_DEQUEUE) | ||
315 | return blkio_fill_stat(key_str, MAX_KEY_LEN - 1, | ||
316 | blkg->stats.dequeue, cb, dev); | ||
317 | #endif | ||
291 | 318 | ||
292 | for (type = 0; type < IO_TYPE_MAX; type++) { | 319 | for (sub_type = BLKIO_STAT_READ; sub_type < BLKIO_STAT_TOTAL; |
293 | get_key_name(type, disk_id, key_str, MAX_KEY_LEN); | 320 | sub_type++) { |
294 | cb->fill(cb, key_str, getvar(blkg, type)); | 321 | blkio_get_key_name(sub_type, dev, key_str, MAX_KEY_LEN, false); |
322 | cb->fill(cb, key_str, blkg->stats.stat_arr[type][sub_type]); | ||
295 | } | 323 | } |
296 | disk_total = getvar(blkg, IO_READ) + getvar(blkg, IO_WRITE); | 324 | disk_total = blkg->stats.stat_arr[type][BLKIO_STAT_READ] + |
297 | get_key_name(IO_TYPE_MAX, disk_id, key_str, MAX_KEY_LEN); | 325 | blkg->stats.stat_arr[type][BLKIO_STAT_WRITE]; |
326 | blkio_get_key_name(BLKIO_STAT_TOTAL, dev, key_str, MAX_KEY_LEN, false); | ||
298 | cb->fill(cb, key_str, disk_total); | 327 | cb->fill(cb, key_str, disk_total); |
299 | return disk_total; | 328 | return disk_total; |
300 | } | 329 | } |
301 | 330 | ||
302 | uint64_t get_stat(struct blkio_group *blkg, struct cgroup_map_cb *cb, | 331 | #define SHOW_FUNCTION_PER_GROUP(__VAR, type, show_total) \ |
303 | get_var *getvar, char *disk_id) | ||
304 | { | ||
305 | uint64_t var = getvar(blkg, 0); | ||
306 | cb->fill(cb, disk_id, var); | ||
307 | return var; | ||
308 | } | ||
309 | |||
310 | #define GET_STAT_INDEXED(__VAR) \ | ||
311 | uint64_t get_##__VAR##_stat(struct blkio_group *blkg, int type) \ | ||
312 | { \ | ||
313 | return blkg->stats.__VAR[type]; \ | ||
314 | } \ | ||
315 | |||
316 | GET_STAT_INDEXED(io_service_bytes); | ||
317 | GET_STAT_INDEXED(io_serviced); | ||
318 | GET_STAT_INDEXED(io_service_time); | ||
319 | GET_STAT_INDEXED(io_wait_time); | ||
320 | #undef GET_STAT_INDEXED | ||
321 | |||
322 | #define GET_STAT(__VAR, __CONV) \ | ||
323 | uint64_t get_##__VAR##_stat(struct blkio_group *blkg, int dummy) \ | ||
324 | { \ | ||
325 | uint64_t data = blkg->stats.__VAR; \ | ||
326 | if (__CONV) \ | ||
327 | data = (uint64_t)jiffies_to_msecs(data) * NSEC_PER_MSEC;\ | ||
328 | return data; \ | ||
329 | } | ||
330 | |||
331 | GET_STAT(time, 1); | ||
332 | GET_STAT(sectors, 0); | ||
333 | #ifdef CONFIG_DEBUG_BLK_CGROUP | ||
334 | GET_STAT(dequeue, 0); | ||
335 | #endif | ||
336 | #undef GET_STAT | ||
337 | |||
338 | #define SHOW_FUNCTION_PER_GROUP(__VAR, get_stats, getvar, show_total) \ | ||
339 | static int blkiocg_##__VAR##_read(struct cgroup *cgroup, \ | 332 | static int blkiocg_##__VAR##_read(struct cgroup *cgroup, \ |
340 | struct cftype *cftype, struct cgroup_map_cb *cb) \ | 333 | struct cftype *cftype, struct cgroup_map_cb *cb) \ |
341 | { \ | 334 | { \ |
@@ -343,7 +336,6 @@ static int blkiocg_##__VAR##_read(struct cgroup *cgroup, \ | |||
343 | struct blkio_group *blkg; \ | 336 | struct blkio_group *blkg; \ |
344 | struct hlist_node *n; \ | 337 | struct hlist_node *n; \ |
345 | uint64_t cgroup_total = 0; \ | 338 | uint64_t cgroup_total = 0; \ |
346 | char disk_id[10]; \ | ||
347 | \ | 339 | \ |
348 | if (!cgroup_lock_live_group(cgroup)) \ | 340 | if (!cgroup_lock_live_group(cgroup)) \ |
349 | return -ENODEV; \ | 341 | return -ENODEV; \ |
@@ -353,10 +345,8 @@ static int blkiocg_##__VAR##_read(struct cgroup *cgroup, \ | |||
353 | hlist_for_each_entry_rcu(blkg, n, &blkcg->blkg_list, blkcg_node) {\ | 345 | hlist_for_each_entry_rcu(blkg, n, &blkcg->blkg_list, blkcg_node) {\ |
354 | if (blkg->dev) { \ | 346 | if (blkg->dev) { \ |
355 | spin_lock_irq(&blkg->stats_lock); \ | 347 | spin_lock_irq(&blkg->stats_lock); \ |
356 | snprintf(disk_id, 10, "%u:%u", MAJOR(blkg->dev),\ | 348 | cgroup_total += blkio_get_stat(blkg, cb, \ |
357 | MINOR(blkg->dev)); \ | 349 | blkg->dev, type); \ |
358 | cgroup_total += get_stats(blkg, cb, getvar, \ | ||
359 | disk_id); \ | ||
360 | spin_unlock_irq(&blkg->stats_lock); \ | 350 | spin_unlock_irq(&blkg->stats_lock); \ |
361 | } \ | 351 | } \ |
362 | } \ | 352 | } \ |
@@ -367,16 +357,14 @@ static int blkiocg_##__VAR##_read(struct cgroup *cgroup, \ | |||
367 | return 0; \ | 357 | return 0; \ |
368 | } | 358 | } |
369 | 359 | ||
370 | SHOW_FUNCTION_PER_GROUP(time, get_stat, get_time_stat, 0); | 360 | SHOW_FUNCTION_PER_GROUP(time, BLKIO_STAT_TIME, 0); |
371 | SHOW_FUNCTION_PER_GROUP(sectors, get_stat, get_sectors_stat, 0); | 361 | SHOW_FUNCTION_PER_GROUP(sectors, BLKIO_STAT_SECTORS, 0); |
372 | SHOW_FUNCTION_PER_GROUP(io_service_bytes, get_typed_stat, | 362 | SHOW_FUNCTION_PER_GROUP(io_service_bytes, BLKIO_STAT_SERVICE_BYTES, 1); |
373 | get_io_service_bytes_stat, 1); | 363 | SHOW_FUNCTION_PER_GROUP(io_serviced, BLKIO_STAT_SERVICED, 1); |
374 | SHOW_FUNCTION_PER_GROUP(io_serviced, get_typed_stat, get_io_serviced_stat, 1); | 364 | SHOW_FUNCTION_PER_GROUP(io_service_time, BLKIO_STAT_SERVICE_TIME, 1); |
375 | SHOW_FUNCTION_PER_GROUP(io_service_time, get_typed_stat, | 365 | SHOW_FUNCTION_PER_GROUP(io_wait_time, BLKIO_STAT_WAIT_TIME, 1); |
376 | get_io_service_time_stat, 1); | ||
377 | SHOW_FUNCTION_PER_GROUP(io_wait_time, get_typed_stat, get_io_wait_time_stat, 1); | ||
378 | #ifdef CONFIG_DEBUG_BLK_CGROUP | 366 | #ifdef CONFIG_DEBUG_BLK_CGROUP |
379 | SHOW_FUNCTION_PER_GROUP(dequeue, get_stat, get_dequeue_stat, 0); | 367 | SHOW_FUNCTION_PER_GROUP(dequeue, BLKIO_STAT_DEQUEUE, 0); |
380 | #endif | 368 | #endif |
381 | #undef SHOW_FUNCTION_PER_GROUP | 369 | #undef SHOW_FUNCTION_PER_GROUP |
382 | 370 | ||
@@ -398,32 +386,30 @@ struct cftype blkio_files[] = { | |||
398 | { | 386 | { |
399 | .name = "time", | 387 | .name = "time", |
400 | .read_map = blkiocg_time_read, | 388 | .read_map = blkiocg_time_read, |
401 | .write_u64 = blkiocg_reset_write, | ||
402 | }, | 389 | }, |
403 | { | 390 | { |
404 | .name = "sectors", | 391 | .name = "sectors", |
405 | .read_map = blkiocg_sectors_read, | 392 | .read_map = blkiocg_sectors_read, |
406 | .write_u64 = blkiocg_reset_write, | ||
407 | }, | 393 | }, |
408 | { | 394 | { |
409 | .name = "io_service_bytes", | 395 | .name = "io_service_bytes", |
410 | .read_map = blkiocg_io_service_bytes_read, | 396 | .read_map = blkiocg_io_service_bytes_read, |
411 | .write_u64 = blkiocg_reset_write, | ||
412 | }, | 397 | }, |
413 | { | 398 | { |
414 | .name = "io_serviced", | 399 | .name = "io_serviced", |
415 | .read_map = blkiocg_io_serviced_read, | 400 | .read_map = blkiocg_io_serviced_read, |
416 | .write_u64 = blkiocg_reset_write, | ||
417 | }, | 401 | }, |
418 | { | 402 | { |
419 | .name = "io_service_time", | 403 | .name = "io_service_time", |
420 | .read_map = blkiocg_io_service_time_read, | 404 | .read_map = blkiocg_io_service_time_read, |
421 | .write_u64 = blkiocg_reset_write, | ||
422 | }, | 405 | }, |
423 | { | 406 | { |
424 | .name = "io_wait_time", | 407 | .name = "io_wait_time", |
425 | .read_map = blkiocg_io_wait_time_read, | 408 | .read_map = blkiocg_io_wait_time_read, |
426 | .write_u64 = blkiocg_reset_write, | 409 | }, |
410 | { | ||
411 | .name = "reset_stats", | ||
412 | .write_u64 = blkiocg_reset_stats, | ||
427 | }, | 413 | }, |
428 | #ifdef CONFIG_DEBUG_BLK_CGROUP | 414 | #ifdef CONFIG_DEBUG_BLK_CGROUP |
429 | { | 415 | { |