Flushes have always been invisible to dm-stats: they carry zero sectors, so dm_stats_account_io() dropped them early. To later support a flush latency histogram, teach the accounting path to let them through:
- introduce the flush I/O class, set for REQ_PREFLUSH bios and REQ_OP_FLUSH requests; - since a data-less flush covers no sector range, account it to the first step-sized area of the region, and only when some histogram of the region subscribes to the flush class; - keep the classic counters (ios, sectors, merges, ticks, in_flight and the merge detection state) untouched by data-less flushes, so the existing output does not change; - only account flush completions: in-flight tracking is left to the read/write counters. https://virtuozzo.atlassian.net/browse/VSTOR-103846 Signed-off-by: Andrey Zhadchenko <[email protected]> --- drivers/md/dm-stats.c | 39 ++++++++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/drivers/md/dm-stats.c b/drivers/md/dm-stats.c index b8546744950f3..4e6667322c0a2 100644 --- a/drivers/md/dm-stats.c +++ b/drivers/md/dm-stats.c @@ -46,6 +46,7 @@ struct dm_stat_shared { enum { DM_STAT_CLASS_READ, DM_STAT_CLASS_WRITE, + DM_STAT_CLASS_FLUSH, DM_STAT_NR_CLASSES, }; @@ -638,6 +639,9 @@ static unsigned int dm_stat_io_classes(blk_opf_t bi_opf, unsigned int bi_sectors if (bi_sectors) classes |= 1 << (op_is_write(bi_opf) ? DM_STAT_CLASS_WRITE : DM_STAT_CLASS_READ); + if ((bi_opf & REQ_PREFLUSH) || + (bi_opf & REQ_OP_MASK) == REQ_OP_FLUSH) + classes |= 1 << DM_STAT_CLASS_FLUSH; return classes; } @@ -674,6 +678,7 @@ static void dm_stat_for_entry(struct dm_stat *s, size_t entry, struct dm_stat_shared *shared = &s->stat_shared[entry]; struct dm_stat_percpu *p; int idx = op_is_write(bi_opf); + bool data = classes & DM_STAT_CLASSES_DATA; /* * For strict correctness we should use local_irq_save/restore @@ -701,21 +706,26 @@ static void dm_stat_for_entry(struct dm_stat *s, size_t entry, if (!end) { dm_stat_round(s, shared, p); - atomic_inc(&shared->in_flight[idx]); + if (likely(data)) + atomic_inc(&shared->in_flight[idx]); } else { unsigned long long duration; unsigned int hmask = s->hist_mask[classes]; dm_stat_round(s, shared, p); - atomic_dec(&shared->in_flight[idx]); - p->sectors[idx] += len; - p->ios[idx] += 1; - p->merges[idx] += stats_aux->merged; + if (likely(data)) { + atomic_dec(&shared->in_flight[idx]); + p->sectors[idx] += len; + p->ios[idx] += 1; + p->merges[idx] += stats_aux->merged; + } if (!(s->stat_flags & STAT_PRECISE_TIMESTAMPS)) { - p->ticks[idx] += duration_jiffies; + if (likely(data)) + p->ticks[idx] += duration_jiffies; duration = jiffies_to_msecs(duration_jiffies); } else { - p->ticks[idx] += stats_aux->duration_ns; + if (likely(data)) + p->ticks[idx] += stats_aux->duration_ns; duration = stats_aux->duration_ns; } if (hmask) { @@ -743,6 +753,19 @@ static void __dm_stat_bio(struct dm_stat *s, blk_opf_t bi_opf, sector_t rel_sector, offset, todo, fragment_len; size_t entry; + if (unlikely(!(classes & DM_STAT_CLASSES_DATA))) { + /* + * A data-less flush covers no sector range, so region + * boundaries do not apply to it. Account it to the first + * entry of the region, and only if some histogram is + * interested in flushes. + */ + if (end && s->hist_mask[classes]) + dm_stat_for_entry(s, 0, bi_opf, classes, 0, + stats_aux, end, duration_jiffies); + return; + } + if (end_sector <= s->start || bi_sector >= s->end) return; if (unlikely(bi_sector < s->start)) { @@ -792,6 +815,8 @@ void dm_stats_account_io(struct dm_stats *stats, blk_opf_t bi_opf, end_sector = bi_sector + bi_sectors; if (!end) { + if (unlikely(!(classes & DM_STAT_CLASSES_DATA))) + return; /* * A race condition can at worst result in the merged flag being * misrepresented, so we don't have to disable preemption here. -- 2.43.5 _______________________________________________ Devel mailing list [email protected] https://lists.openvz.org/mailman/listinfo/devel
