[Crash-utility] [PATCH] dev: Fix display disk I/O statistics for 4.20

Masayoshi Mizuma msys.mizuma at gmail.com
Mon Jan 7 15:18:02 UTC 2019


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 <m.mizuma at jp.fujitsu.com>
---
 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




More information about the Crash-utility mailing list