[Devel] [PATCH RHEL10 COMMIT] drivers/md/dm-stats: prepare for accounting data-less flushes

Konstantin Khorenko khorenko at virtuozzo.com
Fri Jul 31 15:11:48 MSK 2026


The commit is pushed to "branch-rh10-6.12.0-211.39.1.16.x.vz10-ovz" and will appear at git at bitbucket.org:openvz/vzkernel.git
after rh10-6.12.0-211.39.1.16.1.vz10
------>
commit a924e8536b1ce079f5428abd011f77be9929b1d3
Author: Andrey Zhadchenko <andrey.zhadchenko at virtuozzo.com>
Date:   Mon Jul 27 19:32:52 2026 +0300

    drivers/md/dm-stats: prepare for accounting data-less flushes
    
    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
    Feature: dm-stats: latency and histogram enhancements
    Signed-off-by: Andrey Zhadchenko <andrey.zhadchenko at virtuozzo.com>
    Reviewed-by: Vasileios Almpanis <vasileios.almpanis at virtuozzo.com>
    Reviewed-by: Pavel Tikhomirov <ptikhomirov 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.


More information about the Devel mailing list