[Crash-utility] [PATCH 2/2] Fix for "dev -d|-D" options to correctly display disk I/O statistics

Lianbo Jiang lijiang at redhat.com
Wed Apr 27 03:37:04 UTC 2022


Kernel commit 4e5cc99e1e48 ("blk-mq: manage hctx map via xarray") removed
the "queue_hw_ctx" member from struct request_queue at Linux v5.18-rc1,
and replaced it with a struct xarray "hctx_table".Without the patch,
the "dev -d|-D" options will print an error:

  crash> dev -d
  MAJOR GENDISK            NAME       REQUEST_QUEUE      TOTAL  READ WRITE

  dev: invalid structure member offset: request_queue_queue_hw_ctx

With the patch:
  crash> dev -d
  MAJOR GENDISK            NAME       REQUEST_QUEUE      TOTAL  READ WRITE
      8 ffff892147e4ae00   sda        ffff8922c891aa80     240   135   105

Signed-off-by: Lianbo Jiang <lijiang at redhat.com>
---
 defs.h    |  1 +
 dev.c     | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 symbols.c |  2 ++
 3 files changed, 74 insertions(+)

diff --git a/defs.h b/defs.h
index f3c05fb44e62..fa49e9bdf767 100644
--- a/defs.h
+++ b/defs.h
@@ -2180,6 +2180,7 @@ struct offset_table {                    /* stash of commonly-used offsets */
 	long blk_mq_tags_nr_tags;
 	long blk_mq_tags_rqs;
 	long blk_mq_tags_static_rqs;
+	long request_queue_hctx_table;
 };
 
 struct size_table {         /* stash of commonly-used sizes */
diff --git a/dev.c b/dev.c
index 4d574f06494f..64caaf4bd88d 100644
--- a/dev.c
+++ b/dev.c
@@ -4369,12 +4369,81 @@ sbitmap_word_buf_free:
 	FREEBUF(sbitmap_word_buf);
 }
 
+static void get_used_tags(unsigned long q, struct diskio *io_counts)
+{
+	unsigned long addr = 0;
+	unsigned long cnt = 0, i = 0;
+	struct list_pair *lp = NULL;
+
+	addr = q + OFFSET(request_queue_hctx_table);
+	cnt = do_xarray(addr, XARRAY_COUNT, NULL);
+	lp = (struct list_pair *)GETBUF(sizeof(struct list_pair) * (cnt + 1));
+	if (!lp)
+		error(FATAL, "fail to get memory for list_pair.\n");
+
+	lp[0].index = cnt;
+	cnt = do_xarray(addr, XARRAY_GATHER, lp);
+	for (i = 0; i < cnt; i++) {
+		ulong tags = 0, sched_tags = 0;
+		unsigned long *rqs = NULL, *static_rqs = NULL;
+		struct blk_mq_tags_context tags_ctx = {0};
+		struct blk_mq_tags_context sched_tags_ctx = {0};
+
+		if(!IS_KVADDR((ulong)lp[i].value))
+			continue;
+
+		addr = (ulong)lp[i].value + OFFSET(blk_mq_hw_ctx_tags);
+		if (!readmem(addr, KVADDR, &tags, sizeof(ulong),
+				"blk_mq_hw_ctx.tags", RETURN_ON_ERROR))
+			goto lp_free;
+
+		addr = (ulong)lp[i].value + OFFSET(blk_mq_hw_ctx_sched_tags);
+		if (!readmem(addr, KVADDR, &sched_tags, sizeof(ulong),
+				"blk_mq_hw_ctx.sched_tags", RETURN_ON_ERROR))
+			goto lp_free;
+
+		if (IS_KVADDR(tags)) {
+			load_blk_mq_tags_context(tags, &tags_ctx);
+			load_blk_mq_rqs(tags_ctx.rqs, tags_ctx.nr_tags, &rqs);
+			if (!rqs)
+				goto next;
+			find_mq_diskio_by_parsing_bitmap(q, tags_ctx.breserved_tags, 0, rqs, &io_counts);
+			find_mq_diskio_by_parsing_bitmap(q, tags_ctx.bitmap_tags, tags_ctx.nr_reserved_tags,
+							rqs, &io_counts);
+			FREEBUF(rqs);
+		}
+	next:
+		if (IS_KVADDR(sched_tags)) {
+			load_blk_mq_tags_context(sched_tags, &sched_tags_ctx);
+			load_blk_mq_rqs(sched_tags_ctx.static_rqs, sched_tags_ctx.nr_tags, &static_rqs);
+			if (!static_rqs)
+				continue;
+			find_mq_diskio_by_parsing_bitmap(q, sched_tags_ctx.breserved_tags, 0, static_rqs, &io_counts);
+			find_mq_diskio_by_parsing_bitmap(q, sched_tags_ctx.bitmap_tags, sched_tags_ctx.nr_reserved_tags,
+							static_rqs, &io_counts);
+			FREEBUF(static_rqs);
+		}
+	}
+
+lp_free:
+	FREEBUF(lp);
+}
+
 static void get_mq_diskio_from_hw_queues(unsigned long q, struct diskio *io_counts)
 {
 	unsigned long *queue_hw_ctx = NULL;
 	unsigned long addr = 0;
 	unsigned int i, nr_hw_queues;
 
+	if (MEMBER_EXISTS("request_queue", "hctx_table")) {
+		struct diskio tmp = {0};
+
+		get_used_tags(q, &tmp);
+		io_counts->read = tmp.read;
+		io_counts->write = tmp.write;
+		return;
+	}
+
 	addr = q + OFFSET(request_queue_nr_hw_queues);
 	readmem(addr, KVADDR, &nr_hw_queues, sizeof(uint),
 		"request_queue.nr_hw_queues", FAULT_ON_ERROR);
@@ -4804,6 +4873,8 @@ void diskio_init(void)
 			"request_queue", "queue_hw_ctx");
 		MEMBER_OFFSET_INIT(request_queue_nr_hw_queues,
 			"request_queue", "nr_hw_queues");
+		MEMBER_OFFSET_INIT(request_queue_hctx_table,
+				"request_queue", "hctx_table");
 		MEMBER_OFFSET_INIT(blk_mq_ctx_rq_dispatched, "blk_mq_ctx",
 			"rq_dispatched");
 		MEMBER_OFFSET_INIT(blk_mq_ctx_rq_completed, "blk_mq_ctx",
diff --git a/symbols.c b/symbols.c
index 0612255b6e34..e1d8320c48bb 100644
--- a/symbols.c
+++ b/symbols.c
@@ -10401,6 +10401,8 @@ dump_offset_table(char *spec, ulong makestruct)
 		OFFSET(request_queue_queue_hw_ctx));
 	fprintf(fp, "       request_queue_nr_hw_queues: %ld\n",
 		OFFSET(request_queue_nr_hw_queues));
+	fprintf(fp, "       request_queue_hctx_table: %ld\n",
+		OFFSET(request_queue_hctx_table));
 	fprintf(fp, "      blk_mq_ctx_rq_dispatched: %ld\n",
 		OFFSET(blk_mq_ctx_rq_dispatched));
 	fprintf(fp, "       blk_mq_ctx_rq_completed: %ld\n",
-- 
2.20.1



More information about the Crash-utility mailing list