Improvement -d option of dev command to display I/O statics
for the disk which the device driver uses blk-mq interface.
Current dev -d displays always 0 in the all fields for the
blk-mq disk because blk-mq does not increment/decrement to
request_list.count[2] on I/O creation and I/O completion.
The following value is used in blk-mq on such situation.
- I/O creation: blk_mq_ctx.rq_dispatched[2]
- I/O completion: blk_mq_ctx.rq_completed[2]
So, we can get the counter of in progress I/Os as follows.
in progress I/Os == rq_dispatched - rq_completed
This patch displays the result of above calculation for the
disk. It judges as the device driver uses blk-mq if the
request_queue.mq_ops is not NULL.
"DRV" field is displayed as "N/A(MQ)" because the value for in-flight
in the device driver is not exists for blk-mq...
Signed-off-by: Masayoshi Mizuma <m.mizuma(a)jp.fujitsu.com>
---
defs.h | 4 +++
dev.c | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------
help.c | 4 ++-
3 files changed, 96 insertions(+), 10 deletions(-)
diff --git a/defs.h b/defs.h
index a09fa9a..55c28c5 100755
--- a/defs.h
+++ b/defs.h
@@ -1822,6 +1822,10 @@ struct offset_table { /* stash of commonly-used
offsets */
long request_list_count;
long request_queue_in_flight;
long request_queue_rq;
+ long request_queue_mq_ops;
+ long request_queue_queue_ctx;
+ long blk_mq_ctx_rq_dispatched;
+ long blk_mq_ctx_rq_completed;
long subsys_private_klist_devices;
long subsystem_kset;
long mount_mnt_parent;
diff --git a/dev.c b/dev.c
index c18f40e..e46081e 100644
--- a/dev.c
+++ b/dev.c
@@ -3800,18 +3800,84 @@ again:
return i->get_gendisk(klist_node_address);
}
+static int
+use_mq_interface(unsigned long q)
+{
+ unsigned long mq_ops;
+
+ if (!VALID_MEMBER(request_queue_mq_ops))
+ return 0;
+
+ readmem(q + OFFSET(request_queue_mq_ops), KVADDR, &mq_ops,
+ sizeof(ulong), "request_queue.mq_ops", FAULT_ON_ERROR);
+
+ if (mq_ops == 0)
+ return 0;
+ else
+ return 1;
+}
+
+static void
+get_one_mctx_diskio(unsigned long mctx, struct diskio *io)
+{
+ unsigned long dispatch[2];
+ unsigned long comp[2];
+
+ readmem(mctx + OFFSET(blk_mq_ctx_rq_dispatched),
+ KVADDR, dispatch, sizeof(ulong) * 2, "blk_mq_ctx.rq_dispatched",
+ FAULT_ON_ERROR);
+
+ readmem(mctx + OFFSET(blk_mq_ctx_rq_completed),
+ KVADDR, comp, sizeof(ulong) * 2, "blk_mq_ctx.rq_completed",
+ FAULT_ON_ERROR);
+
+ io->read = (dispatch[0] - comp[0]);
+ io->write = (dispatch[1] - comp[1]);
+}
+
+static void
+get_mq_diskio(unsigned long q, unsigned long *mq_count)
+{
+ int cpu;
+ unsigned long queue_ctx;
+ unsigned long mctx_addr;
+ struct diskio tmp;
+
+ memset(&tmp, 0x00, sizeof(struct diskio));
+
+ readmem(q + OFFSET(request_queue_queue_ctx), KVADDR, &queue_ctx,
+ sizeof(ulong), "request_queue.queue_ctx",
+ FAULT_ON_ERROR);
+
+ for (cpu = 0; cpu < kt->cpus; cpu++) {
+ if ((kt->flags & SMP) && (kt->flags & PER_CPU_OFF)) {
+ mctx_addr = queue_ctx + kt->__per_cpu_offset[cpu];
+ get_one_mctx_diskio(mctx_addr, &tmp);
+ mq_count[0] += tmp.read;
+ mq_count[1] += tmp.write;
+ }
+ }
+}
+
/* read request_queue.rq.count[2] */
static void
get_diskio_1(unsigned long rq, struct diskio *io)
{
int count[2];
+ unsigned long mq_count[2] = { 0 };
- readmem(rq + OFFSET(request_queue_rq) + OFFSET(request_list_count),
- KVADDR, count, sizeof(int) * 2, "request_list.count",
- FAULT_ON_ERROR);
+ if (!use_mq_interface(rq)) {
+ readmem(rq + OFFSET(request_queue_rq) +
+ OFFSET(request_list_count), KVADDR, count,
+ sizeof(int) * 2, "request_list.count", FAULT_ON_ERROR);
- io->read = count[0];
- io->write = count[1];
+ io->read = count[0];
+ io->write = count[1];
+ } else {
+ get_mq_diskio(rq, mq_count);
+ io->read = mq_count[0];
+ io->write = mq_count[1];
+ }
}
/* request_queue.in_flight contains total requests */
@@ -3961,9 +4027,8 @@ display_one_diskio(struct iter *i, unsigned long gendisk)
readmem(gendisk + OFFSET(gendisk_major), KVADDR, &major, sizeof(int),
"gen_disk.major", FAULT_ON_ERROR);
i->get_diskio(queue_addr, &io);
- in_flight = i->get_in_flight(queue_addr);
- fprintf(fp, "%s%s%s %s%s%s%s %s%5d%s%s%s%s%s%5u\n",
+ fprintf(fp, "%s%s%s %s%s%s%s %s%5d%s%s%s%s%s",
mkstring(buf0, 5, RJUST|INT_DEC, (char *)(unsigned long)major),
space(MINSPACE),
mkstring(buf1, VADDR_PRLEN, LJUST|LONG_HEX, (char *)gendisk),
@@ -3980,8 +4045,13 @@ display_one_diskio(struct iter *i, unsigned long gendisk)
space(MINSPACE),
mkstring(buf5, 5, RJUST|INT_DEC,
(char *)(unsigned long)io.write),
- space(MINSPACE),
- in_flight);
+ space(MINSPACE));
+
+ if (!use_mq_interface(queue_addr)) {
+ in_flight = i->get_in_flight(queue_addr);
+ fprintf(fp, "%5u\n", in_flight);
+ } else
+ fprintf(fp, "%s\n", "N/A(MQ)");
}
static void
@@ -4056,6 +4126,16 @@ void diskio_init(void)
MEMBER_OFFSET_INIT(request_queue_rq, "request_queue", "rq");
else
MEMBER_OFFSET_INIT(request_queue_rq, "request_queue", "root_rl");
+ if (MEMBER_EXISTS("request_queue", "mq_ops")) {
+ MEMBER_OFFSET_INIT(request_queue_mq_ops, "request_queue",
+ "mq_ops");
+ ANON_MEMBER_OFFSET_INIT(request_queue_queue_ctx,
+ "request_queue", "queue_ctx");
+ MEMBER_OFFSET_INIT(blk_mq_ctx_rq_dispatched, "blk_mq_ctx",
+ "rq_dispatched");
+ MEMBER_OFFSET_INIT(blk_mq_ctx_rq_completed, "blk_mq_ctx",
+ "rq_completed");
+ }
MEMBER_OFFSET_INIT(subsys_private_klist_devices, "subsys_private",
"klist_devices");
MEMBER_OFFSET_INIT(subsystem_kset, "subsystem", "kset");
diff --git a/help.c b/help.c
index 938251f..cfa0516 100644
--- a/help.c
+++ b/help.c
@@ -2684,7 +2684,9 @@ char *help_dev[] = {
" ASYNC: I/O requests that are asynchronous",
" READ: I/O requests that are reads (older kernels)",
" WRITE: I/O requests that are writes (older kernels)",
-" DRV: I/O requests that are in-flight in the device driver",
+" DRV: I/O requests that are in-flight in the device driver.",
+" If the device driver uses blk-mq interface, this field",
+" shows N/A(MQ).",
"\nEXAMPLES",
" Display character and block device data:\n",
" %s> dev",
--
1.8.3.1