Fix for the "dev -d|-D" command on Linux 4.20 and later kernels.
In Linux 4.20, in_flight member in struct request_queue is disappeared.
And also struct request_list is removed. So, dev -d|-D doesn't work.

Unfortunately, it seems that there is no alternative information
which shows the number of I/Os issued to disk driver. So this patch
gets DRV column removed if in_flight member in struct request_queue
isn't valid.

Without the patch, the command fails with the error message
"dev: -d option not supported or applicable on this architecture
or kernel".

Signed-off-by: Masayoshi Mizuma <[email protected]>
---
 defs.h    |  2 ++
 dev.c     | 73 ++++++++++++++++++++++++++++++++++++++++---------------
 symbols.c |  4 +++
 3 files changed, 59 insertions(+), 20 deletions(-)

diff --git a/defs.h b/defs.h
index a3cb5a4..9ebdde6 100644
--- a/defs.h
+++ b/defs.h
@@ -2064,6 +2064,8 @@ struct offset_table {                    /* stash of 
commonly-used offsets */
        long xarray_xa_head;
        long xa_node_slots;
        long xa_node_shift;
+       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/symbols.c b/symbols.c
index ef6f934..5f77e27 100644
--- a/symbols.c
+++ b/symbols.c
@@ -10101,6 +10101,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",
-- 
2.18.1

--
Crash-utility mailing list
[email protected]
https://www.redhat.com/mailman/listinfo/crash-utility

Reply via email to