commit 361f050e3148c6188afb45942e06d4a509852b86 Author: Dave Anderson Date: Mon Jan 7 13:56:15 2019 -0500 Fix for the "dev -[dD]" options in kernels containing Linux 5.0-rc1 commit 7ff4f8035695984c513598e2d49c8277d5d234ca, titled "block: remove dead queue members", in which the number of I/Os issued to a disk driver are no longer stored in the request_queue structure. Without the patch, the options indicate "dev: -d option not supported or applicable on this architecture or kernel". With the patch, the "DRV" column is not shown. (m.mizuma@jp.fujitsu.com) diff --git a/defs.h b/defs.h index a3cb5a4..9ebdde6 100644 --- a/defs.h +++ b/defs.h @@ -2043,6 +2043,8 @@ struct offset_table { long pci_bus_self; long device_kobj; long kobject_name; + long hd_struct_dkstats; + long disk_stats_in_flight; }; struct size_table { /* stash of commonly-used sizes */ diff --git a/dev.c b/dev.c index 7ce2422..24efea2 100644 --- a/dev.c +++ b/dev.c @@ -3974,7 +3974,7 @@ struct iter { * this function reads request_list.count[2], and the first argument * is the address of request_queue. */ - void (*get_diskio)(unsigned long , struct diskio *); + void (*get_diskio)(unsigned long , unsigned long, struct diskio *); /* * check if device.type == &disk_type @@ -4187,24 +4187,55 @@ get_mq_diskio(unsigned long q, unsigned long *mq_count) } } +static void +get_one_diskio_from_dkstats(unsigned long dkstats, unsigned long *count) +{ + int cpu; + unsigned long dkstats_addr; + unsigned long in_flight[2]; + + for (cpu = 0; cpu < kt->cpus; cpu++) { + if ((kt->flags & SMP) && (kt->flags & PER_CPU_OFF)) { + dkstats_addr = dkstats + kt->__per_cpu_offset[cpu]; + readmem(dkstats_addr + OFFSET(disk_stats_in_flight), + KVADDR, in_flight, sizeof(long) * 2, + "disk_stats.in_flight", FAULT_ON_ERROR); + count[0] += in_flight[0]; + count[1] += in_flight[1]; + } + } +} + + /* read request_queue.rq.count[2] */ static void -get_diskio_1(unsigned long rq, struct diskio *io) +get_diskio_1(unsigned long rq, unsigned long gendisk, struct diskio *io) { int count[2]; - unsigned long mq_count[2] = { 0 }; + unsigned long io_counts[2] = { 0 }; + unsigned long dkstats; 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); + if (VALID_MEMBER(request_queue_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]; + } else { + readmem(gendisk + OFFSET(gendisk_part0) + + OFFSET(hd_struct_dkstats), KVADDR, &dkstats, + sizeof(ulong), "gendisk.part0.dkstats", FAULT_ON_ERROR); + get_one_diskio_from_dkstats(dkstats, io_counts); - io->read = count[0]; - io->write = count[1]; + io->read = io_counts[0]; + io->write = io_counts[1]; + } } else { - get_mq_diskio(rq, mq_count); - io->read = mq_count[0]; - io->write = mq_count[1]; + get_mq_diskio(rq, io_counts); + io->read = io_counts[0]; + io->write = io_counts[1]; } } @@ -4250,9 +4281,6 @@ init_iter(struct iter *i) i->get_in_flight = get_in_flight_1; } else if (SIZE(rq_in_flight) == sizeof(int) * 2) { i->get_in_flight = get_in_flight_2; - } else { - option_not_supported('d'); - return; } i->get_diskio = get_diskio_1; @@ -4354,7 +4382,7 @@ display_one_diskio(struct iter *i, unsigned long gendisk, ulong flags) sizeof(ulong), "gen_disk.queue", FAULT_ON_ERROR); readmem(gendisk + OFFSET(gendisk_major), KVADDR, &major, sizeof(int), "gen_disk.major", FAULT_ON_ERROR); - i->get_diskio(queue_addr, &io); + i->get_diskio(queue_addr, gendisk, &io); if ((flags & DIOF_NONZERO) && (io.read + io.write == 0)) @@ -4379,11 +4407,14 @@ display_one_diskio(struct iter *i, unsigned long gendisk, ulong flags) (char *)(unsigned long)io.write), space(MINSPACE)); - if (!use_mq_interface(queue_addr)) { - in_flight = i->get_in_flight(queue_addr); - fprintf(fp, "%5u\n", in_flight); + if (VALID_MEMBER(request_queue_in_flight)) { + 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)"); } else - fprintf(fp, "%s\n", "N/A(MQ)"); + fprintf(fp, "\n"); } static void @@ -4418,7 +4449,7 @@ display_all_diskio(ulong flags) i.sync_count ? mkstring(buf4, 5, RJUST, "SYNC") : mkstring(buf4, 5, RJUST, "WRITE"), space(MINSPACE), - mkstring(buf5, 5, RJUST, "DRV")); + VALID_MEMBER(request_queue_in_flight) ? mkstring(buf5, 5, RJUST, "DRV") : ""); while ((gendisk = i.next_disk(&i)) != 0) display_one_diskio(&i, gendisk, flags); @@ -4446,6 +4477,7 @@ void diskio_init(void) MEMBER_OFFSET_INIT(gendisk_part0, "gendisk", "part0"); MEMBER_OFFSET_INIT(gendisk_queue, "gendisk", "queue"); MEMBER_OFFSET_INIT(hd_struct_dev, "hd_struct", "__dev"); + MEMBER_OFFSET_INIT(hd_struct_dkstats, "hd_struct", "dkstats"); MEMBER_OFFSET_INIT(klist_k_list, "klist", "k_list"); MEMBER_OFFSET_INIT(klist_node_n_klist, "klist_node", "n_klist"); MEMBER_OFFSET_INIT(klist_node_n_node, "klist_node", "n_node"); @@ -4476,6 +4508,7 @@ void diskio_init(void) MEMBER_SIZE_INIT(rq_in_flight, "request_queue", "in_flight"); MEMBER_SIZE_INIT(class_private_devices, "class_private", "class_devices"); + MEMBER_OFFSET_INIT(disk_stats_in_flight, "disk_stats", "in_flight"); dt->flags |= DISKIO_INIT; } diff --git a/help.c b/help.c index aadd2ed..1593e82 100644 --- a/help.c +++ b/help.c @@ -3218,7 +3218,7 @@ char *help_dev[] = { " WRITE: I/O requests that are writes (older kernels)", " 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).", +" shows N/A(MQ). If not available, this column is not shown.", " -D same as -d, but filter out disks with no in-progress I/O requests.", "\nEXAMPLES", " Display character and block device data:\n", diff --git a/symbols.c b/symbols.c index ef6f934..5f77e27 100644 --- a/symbols.c +++ b/symbols.c @@ -10021,6 +10021,10 @@ dump_offset_table(char *spec, ulong makestruct) OFFSET(gendisk_queue)); fprintf(fp, " hd_struct_dev: %ld\n", OFFSET(hd_struct_dev)); + fprintf(fp, " hd_struct_dkstats: %ld\n", + OFFSET(hd_struct_dkstats)); + fprintf(fp, " disk_stats_in_flight: %ld\n", + OFFSET(disk_stats_in_flight)); fprintf(fp, " klist_k_list: %ld\n", OFFSET(klist_k_list)); fprintf(fp, " klist_node_n_klist: %ld\n",