[Devel] [PATCH VZ10 v2 09/11] drivers/md/dm-stats: prepare for accounting data-less flushes

Andrey Zhadchenko andrey.zhadchenko at virtuozzo.com
Mon Jul 27 19:32:52 MSK 2026


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 <andrey.zhadchenko at virtuozzo.com>
---
 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 9c2f290843bae..1899549748cc3 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,
 };
 
@@ -639,6 +640,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;
 			if ((s->stat_flags & STAT_HIST_TOTAL_LATENCY) &&
 			    stats_aux->histogram_duration_ns)
 				duration = stats_aux->histogram_duration_ns;
@@ -742,6 +752,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)) {
@@ -791,6 +814,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



More information about the Devel mailing list