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@xxxxxxxxxxxxxx> --- 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 -- Crash-utility mailing list Crash-utility@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/crash-utility