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

Reply via email to