From 94bcc688b0a0bbf262c0822e295fc43988005889 Mon Sep 17 00:00:00 2001 From: Mike Snitzer Date: Mon, 5 Aug 2013 18:07:59 -0400 Subject: [PATCH 7/9] dm cache: add @stats_clear message factored out reuseable code to share between print and clear --- Documentation/device-mapper/dm-statistics.txt | 15 ++- drivers/md/dm-stats.c | 141 +++++++++++++++++-------- 2 files changed, 106 insertions(+), 50 deletions(-) diff --git a/Documentation/device-mapper/dm-statistics.txt b/Documentation/device-mapper/dm-statistics.txt index 6578741..3ec2584 100644 --- a/Documentation/device-mapper/dm-statistics.txt +++ b/Documentation/device-mapper/dm-statistics.txt @@ -37,6 +37,11 @@ Messages use this value for anything. @stats_create message creates new region and returns the region id. +@stats_clear + + region id returned from @stats_create +Clears all the counters except the in-flight i/o counters. + @stats_print [ ] Region id returned from @stats_create @@ -64,10 +69,12 @@ Additional counters: The number of lines in the output. If omitted, all lines are returned. -@stats_print_clear prints the counters (like @stats_print) and clears -all the counters except the in-flight i/o counters. If -and are specified, only the statistics on the lines -that were returned are cleared. +@stats_print_clear atomically prints the counters (like @stats_print) +and clears all the counters except the in-flight i/o counters. Useful +when client consuming the statistics does not want to lose any +statistics (between printing and clearing). If and + are specified, only the statistics on the lines that +were returned are cleared. @stats_delete diff --git a/drivers/md/dm-stats.c b/drivers/md/dm-stats.c index fa6dbed..850084e 100644 --- a/drivers/md/dm-stats.c +++ b/drivers/md/dm-stats.c @@ -519,6 +519,79 @@ void dm_stats_bio(struct dm_stats *st, rcu_read_unlock(); } +static void dm_stat_init_temporary_percpu_totals(struct dm_stat_shared *s, + struct dm_stat *m, size_t x) +{ + int cpu; + struct dm_stat_percpu *p; + + local_irq_disable(); + p = &m->stat_percpu[smp_processor_id()][x]; + dm_stat_round(s, p); + local_irq_enable(); + + memset(&s->tmp, 0, sizeof(s->tmp)); + for_each_possible_cpu(cpu) { + p = &m->stat_percpu[cpu][x]; + s->tmp.sectors[0] += p->sectors[0]; + s->tmp.sectors[1] += p->sectors[1]; + s->tmp.ios[0] += p->ios[0]; + s->tmp.ios[1] += p->ios[1]; + s->tmp.ios_merged[0] += p->ios_merged[0]; + s->tmp.ios_merged[1] += p->ios_merged[1]; + s->tmp.ticks[0] += p->ticks[0]; + s->tmp.ticks[1] += p->ticks[1]; + s->tmp.io_ticks[0] += p->io_ticks[0]; + s->tmp.io_ticks[1] += p->io_ticks[1]; + s->tmp.io_ticks_total += p->io_ticks_total; + s->tmp.time_in_queue += p->time_in_queue; + } +} + +static void dm_stat_clear(struct dm_stat *m, size_t idx_start, size_t idx_end, + bool init_tmp_percpu_totals) +{ + size_t x; + struct dm_stat_shared *s; + struct dm_stat_percpu *p; + + for (x = idx_start; x < idx_end; x++) { + s = &m->stat_shared[x]; + if (init_tmp_percpu_totals) + dm_stat_init_temporary_percpu_totals(s, m ,x); + local_irq_disable(); + p = &m->stat_percpu[smp_processor_id()][x]; + p->sectors[0] -= s->tmp.sectors[0]; + p->sectors[1] -= s->tmp.sectors[1]; + p->ios[0] -= s->tmp.ios[0]; + p->ios[1] -= s->tmp.ios[1]; + p->ios_merged[0] -= s->tmp.ios_merged[0]; + p->ios_merged[1] -= s->tmp.ios_merged[1]; + p->ticks[0] -= s->tmp.ticks[0]; + p->ticks[1] -= s->tmp.ticks[1]; + p->io_ticks[0] -= s->tmp.io_ticks[0]; + p->io_ticks[1] -= s->tmp.io_ticks[1]; + p->io_ticks_total -= s->tmp.io_ticks_total; + p->time_in_queue -= s->tmp.time_in_queue; + local_irq_enable(); + } +} + +static int dm_stats_clear(struct dm_stats *st, int id) +{ + struct dm_stat *m; + + m = dm_stats_find(st, id); + if (!m) + return -ENOENT; + + dm_stat_clear(m, 0, m->n_entries, true); + + mutex_unlock(&st->mutex); + + return 1; +} + /* * This is like jiffies_to_msec, but works for 64-bit values. */ @@ -548,6 +621,7 @@ static int dm_stats_print(struct dm_stats *st, int id, size_t x; sector_t start, end; size_t idx_end; + struct dm_stat_shared *s; m = dm_stats_find(st, id); if (!m) @@ -564,35 +638,12 @@ static int dm_stats_print(struct dm_stats *st, int id, start = m->start + m->step * idx_start; for (x = idx_start; x < idx_end; x++, start = end) { - int cpu; - struct dm_stat_shared *s = &m->stat_shared[x]; - struct dm_stat_percpu *p; - + s = &m->stat_shared[x]; end = start + m->step; if (unlikely(end > m->end)) end = m->end; - local_irq_disable(); - p = &m->stat_percpu[smp_processor_id()][x]; - dm_stat_round(s, p); - local_irq_enable(); - - memset(&s->tmp, 0, sizeof(s->tmp)); - for_each_possible_cpu(cpu) { - p = &m->stat_percpu[cpu][x]; - s->tmp.sectors[0] += p->sectors[0]; - s->tmp.sectors[1] += p->sectors[1]; - s->tmp.ios[0] += p->ios[0]; - s->tmp.ios[1] += p->ios[1]; - s->tmp.ios_merged[0] += p->ios_merged[0]; - s->tmp.ios_merged[1] += p->ios_merged[1]; - s->tmp.ticks[0] += p->ticks[0]; - s->tmp.ticks[1] += p->ticks[1]; - s->tmp.io_ticks[0] += p->io_ticks[0]; - s->tmp.io_ticks[1] += p->io_ticks[1]; - s->tmp.io_ticks_total += p->io_ticks_total; - s->tmp.time_in_queue += p->time_in_queue; - } + dm_stat_init_temporary_percpu_totals(s, m, x); DMEMIT("%llu-%llu %llu %llu %llu %llu %llu %llu %llu %llu %d %llu %llu %llu %llu\n", (unsigned long long)start, @@ -615,27 +666,8 @@ static int dm_stats_print(struct dm_stats *st, int id, goto buffer_overflow; } - if (clear) { - for (x = idx_start; x < idx_end; x++) { - struct dm_stat_shared *s = &m->stat_shared[x]; - struct dm_stat_percpu *p; - local_irq_disable(); - p = &m->stat_percpu[smp_processor_id()][x]; - p->sectors[0] -= s->tmp.sectors[0]; - p->sectors[1] -= s->tmp.sectors[1]; - p->ios[0] -= s->tmp.ios[0]; - p->ios[1] -= s->tmp.ios[1]; - p->ios_merged[0] -= s->tmp.ios_merged[0]; - p->ios_merged[1] -= s->tmp.ios_merged[1]; - p->ticks[0] -= s->tmp.ticks[0]; - p->ticks[1] -= s->tmp.ticks[1]; - p->io_ticks[0] -= s->tmp.io_ticks[0]; - p->io_ticks[1] -= s->tmp.io_ticks[1]; - p->io_ticks_total -= s->tmp.io_ticks_total; - p->time_in_queue -= s->tmp.time_in_queue; - local_irq_enable(); - } - } + if (clear) + dm_stat_clear(m, idx_start, idx_end, false); buffer_overflow: mutex_unlock(&st->mutex); @@ -744,6 +776,21 @@ static int message_stats_delete(struct mapped_device *md, return dm_stats_delete(dm_get_stats(md), id); } +static int message_stats_clear(struct mapped_device *md, + unsigned argc, char **argv) +{ + int id; + char dummy; + + if (argc != 2) + return -EINVAL; + + if (sscanf(argv[1], "%d%c", &id, &dummy) != 1 || id < 0) + return -EINVAL; + + return dm_stats_clear(dm_get_stats(md), id); +} + static int message_stats_list(struct mapped_device *md, unsigned argc, char **argv, char *result, unsigned maxlen) @@ -823,6 +870,8 @@ int dm_stats_message(struct mapped_device *md, unsigned argc, char **argv, r = message_stats_create(md, argc, argv, result, maxlen); else if (!strcasecmp(argv[0], "@stats_delete")) r = message_stats_delete(md, argc, argv); + else if (!strcasecmp(argv[0], "@stats_clear")) + r = message_stats_clear(md, argc, argv); else if (!strcasecmp(argv[0], "@stats_list")) r = message_stats_list(md, argc, argv, result, maxlen); else if (!strcasecmp(argv[0], "@stats_print")) -- 1.7.1