From ba2896ac20c9280ce4abb6d7911207edc9ee798e Mon Sep 17 00:00:00 2001
From: Xiaoguang Wang <xiaoguang.wang@linux.alibaba.com>
Date: Wed, 19 Jun 2019 15:03:52 +0800
Subject: [PATCH 0307/2944] alinux: block: add counter to track io request's
 d2c time

Indeed tool iostat's await is not good enough, which is somewhat sketchy
and could not show request's latency on device driver's side.

Here we add a new counter to track io request's d2c time, also with this
patch, we can extend iostat to show this value easily.

Note:
I had checked how iostat is implemented, it just reads fields it needs,
so iostat won't be affected by this change, so does tsar.

Reviewed-by: Joseph Qi <joseph.qi@linux.alibaba.com>
Signed-off-by: Xiaoguang Wang <xiaoguang.wang@linux.alibaba.com>
Signed-off-by: Joseph Qi <joseph.qi@linux.alibaba.com>
Acked-by: Caspar Zhang <caspar@linux.alibaba.com>
---
 Documentation/iostats.txt | 18 ++++++++++++++++++
 block/blk-core.c          |  3 +++
 block/genhd.c             |  7 +++++--
 block/partition-generic.c |  7 +++++--
 include/linux/genhd.h     |  4 ++++
 5 files changed, 35 insertions(+), 4 deletions(-)

diff --git a/Documentation/iostats.txt b/Documentation/iostats.txt
index 49df45f..bc07978 100644
--- a/Documentation/iostats.txt
+++ b/Documentation/iostats.txt
@@ -184,6 +184,24 @@ your ``/etc/fstab``::
 
 	none /sys sysfs defaults 0 0
 
+Field 12 -- # of discards completed
+    This is the total number of discards completed successfully.
+
+Field 13 -- # of discards merged
+    See the description of field 2
+
+Field 14 -- # of sectors discarded
+    This is the total number of sectors discarded successfully.
+
+Field 15 -- # of milliseconds spent discarding
+    This is the total number of milliseconds spent by all discards (as
+    measured from __make_request() to end_that_request_last()).
+
+Field 16 -- # of milliseconds spent reading on device driver's side
+
+Field 17 -- # of milliseconds spent writing on device driver's side
+
+Field 18 -- # of milliseconds spent discarding on device driver's side
 
 In 2.6+, all disk statistics were removed from ``/proc/stat``.  In 2.4, they
 appear in both ``/proc/partitions`` and ``/proc/stat``, although the ones in
diff --git a/block/blk-core.c b/block/blk-core.c
index dddb63d..39971c5 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -2753,6 +2753,9 @@ void blk_account_io_done(struct request *req, u64 now)
 
 		part_stat_inc(cpu, part, ios[sgrp]);
 		part_stat_add(cpu, part, nsecs[sgrp], now - req->start_time_ns);
+		if (req->io_start_time_ns)
+			part_stat_add(cpu, part, d2c_nsecs[sgrp],
+				      now - req->io_start_time_ns);
 		part_round_stats(req->q, cpu, part);
 		part_dec_in_flight(req->q, part, rq_data_dir(req));
 
diff --git a/block/genhd.c b/block/genhd.c
index 2b2a936..ee4da1b 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -1356,7 +1356,7 @@ static int diskstats_show(struct seq_file *seqf, void *v)
 			   "%lu %lu %lu %u "
 			   "%lu %lu %lu %u "
 			   "%u %u %u "
-			   "%lu %lu %lu %u\n",
+			   "%lu %lu %lu %u %u %u %u\n",
 			   MAJOR(part_devt(hd)), MINOR(part_devt(hd)),
 			   disk_name(gp, hd->partno, buf),
 			   part_stat_read(hd, ios[STAT_READ]),
@@ -1373,7 +1373,10 @@ static int diskstats_show(struct seq_file *seqf, void *v)
 			   part_stat_read(hd, ios[STAT_DISCARD]),
 			   part_stat_read(hd, merges[STAT_DISCARD]),
 			   part_stat_read(hd, sectors[STAT_DISCARD]),
-			   (unsigned int)part_stat_read_msecs(hd, STAT_DISCARD)
+			   (unsigned int)part_stat_read_msecs(hd, STAT_DISCARD),
+			   (unsigned int)part_stat_read_d2c_msecs(hd, STAT_READ),
+			   (unsigned int)part_stat_read_d2c_msecs(hd, STAT_WRITE),
+			   (unsigned int)part_stat_read_d2c_msecs(hd, STAT_DISCARD)
 			);
 	}
 	disk_part_iter_exit(&piter);
diff --git a/block/partition-generic.c b/block/partition-generic.c
index 98d60a5..ed4bc5f 100644
--- a/block/partition-generic.c
+++ b/block/partition-generic.c
@@ -131,7 +131,7 @@ ssize_t part_stat_show(struct device *dev,
 		"%8lu %8lu %8llu %8u "
 		"%8lu %8lu %8llu %8u "
 		"%8u %8u %8u "
-		"%8lu %8lu %8llu %8u"
+		"%8lu %8lu %8llu %8u %8u %8u %8u"
 		"\n",
 		part_stat_read(p, ios[STAT_READ]),
 		part_stat_read(p, merges[STAT_READ]),
@@ -147,7 +147,10 @@ ssize_t part_stat_show(struct device *dev,
 		part_stat_read(p, ios[STAT_DISCARD]),
 		part_stat_read(p, merges[STAT_DISCARD]),
 		(unsigned long long)part_stat_read(p, sectors[STAT_DISCARD]),
-		(unsigned int)part_stat_read_msecs(p, STAT_DISCARD));
+		(unsigned int)part_stat_read_msecs(p, STAT_DISCARD),
+		(unsigned int)part_stat_read_d2c_msecs(p, STAT_READ),
+		(unsigned int)part_stat_read_d2c_msecs(p, STAT_WRITE),
+		(unsigned int)part_stat_read_d2c_msecs(p, STAT_DISCARD));
 }
 
 ssize_t part_inflight_show(struct device *dev, struct device_attribute *attr,
diff --git a/include/linux/genhd.h b/include/linux/genhd.h
index 7ce9f29..ebc5408 100644
--- a/include/linux/genhd.h
+++ b/include/linux/genhd.h
@@ -84,6 +84,7 @@ struct partition {
 
 struct disk_stats {
 	u64 nsecs[NR_STAT_GROUPS];
+	u64 d2c_nsecs[NR_STAT_GROUPS];
 	unsigned long sectors[NR_STAT_GROUPS];
 	unsigned long ios[NR_STAT_GROUPS];
 	unsigned long merges[NR_STAT_GROUPS];
@@ -361,6 +362,9 @@ static inline void free_part_stats(struct hd_struct *part)
 #define part_stat_read_msecs(part, which)				\
 	div_u64(part_stat_read(part, nsecs[which]), NSEC_PER_MSEC)
 
+#define part_stat_read_d2c_msecs(part, which)			\
+	div_u64(part_stat_read(part, d2c_nsecs[which]), NSEC_PER_MSEC)
+
 #define part_stat_read_accum(part, field)				\
 	(part_stat_read(part, field[STAT_READ]) +			\
 	 part_stat_read(part, field[STAT_WRITE]) +			\
-- 
1.8.3.1

