[Crash-utility] [PATCH] Fix for the "dev -[dD]" options on Linux 5.1-rc1 and later

Kazuhito Hagio k-hagio at ab.jp.nec.com
Mon Apr 15 17:00:04 UTC 2019


Fix for the "dev -[dD]" options on Linux 5.1-rc1 and later kernels
that contain commit 570d0200123fb4f809aa2f6226e93a458d664d70,
titled "driver core: move device->knode_class to device_private".
Without the patch, the commands fail with the following error message:

  dev: invalid structure member offset: device_knode_class
       FILE: dev.c  LINE: 4046  FUNCTION: match_klist()

Signed-off-by: Kazuhito Hagio <k-hagio at ab.jp.nec.com>
---
 defs.h    |  1 +
 dev.c     | 34 ++++++++++++++++++++++++++++++++--
 symbols.c |  2 ++
 3 files changed, 35 insertions(+), 2 deletions(-)

diff --git a/defs.h b/defs.h
index 2466681..db192f3 100644
--- a/defs.h
+++ b/defs.h
@@ -2068,6 +2068,7 @@ struct offset_table {                    /* stash of commonly-used offsets */
 	long disk_stats_in_flight;
 	long cpu_context_save_r7;
 	long dentry_d_sb;
+	long device_private_knode_class;
 };
 
 struct size_table {         /* stash of commonly-used sizes */
diff --git a/dev.c b/dev.c
index 24efea2..91b81f3 100644
--- a/dev.c
+++ b/dev.c
@@ -4020,6 +4020,21 @@ get_gendisk_4(unsigned long entry)
 		OFFSET(gendisk_part0);
 }
 
+/* kernel version >= 5.1 */
+static unsigned long
+get_gendisk_5(unsigned long entry)
+{
+	unsigned long device_address;
+	unsigned long device_private_address;
+
+	device_private_address = entry - OFFSET(device_private_knode_class);
+	readmem(device_private_address + OFFSET(device_private_device),
+		KVADDR, &device_address, sizeof(device_address),
+		"device_private.device", FAULT_ON_ERROR);
+
+	return device_address - OFFSET(hd_struct_dev) - OFFSET(gendisk_part0);
+}
+
 /* 2.6.24 < kernel version <= 2.6.27 */
 static int 
 match_list(struct iter *i, unsigned long entry)
@@ -4042,8 +4057,18 @@ match_klist(struct iter *i, unsigned long entry)
 {
 	unsigned long device_address;
 	unsigned long device_type;
+	unsigned long device_private_address;
 
-	device_address = entry - OFFSET(device_knode_class);
+	if (VALID_MEMBER(device_knode_class))
+		device_address = entry - OFFSET(device_knode_class);
+	else {
+		/* kernel version >= 5.1 */
+		device_private_address = entry -
+			OFFSET(device_private_knode_class);
+		readmem(device_private_address + OFFSET(device_private_device),
+			KVADDR, &device_address, sizeof(device_address),
+			"device_private.device", FAULT_ON_ERROR);
+	}
 	readmem(device_address + OFFSET(device_type), KVADDR, &device_type,
 		sizeof(device_type), "device.type", FAULT_ON_ERROR);
 	if (device_type != i->type_address)
@@ -4348,8 +4373,10 @@ init_iter(struct iter *i)
 			i->match = match_klist;
 			if (VALID_MEMBER(gendisk_dev))
 				i->get_gendisk = get_gendisk_3;
-			else
+			else if (VALID_MEMBER(device_knode_class))
 				i->get_gendisk = get_gendisk_4;
+			else
+				i->get_gendisk = get_gendisk_5;
 		}
 	} else {
 		option_not_supported('d');
@@ -4470,6 +4497,9 @@ void diskio_init(void)
 	MEMBER_OFFSET_INIT(device_knode_class, "device", "knode_class");
 	MEMBER_OFFSET_INIT(device_node, "device", "node");
 	MEMBER_OFFSET_INIT(device_type, "device", "type");
+	MEMBER_OFFSET_INIT(device_private_device, "device_private", "device");
+	MEMBER_OFFSET_INIT(device_private_knode_class, "device_private",
+		"knode_class");
 	MEMBER_OFFSET_INIT(gendisk_dev, "gendisk", "dev");
 	if (INVALID_MEMBER(gendisk_dev))
 		MEMBER_OFFSET_INIT(gendisk_dev, "gendisk", "__dev");
diff --git a/symbols.c b/symbols.c
index 1ed75fe..da68eda 100644
--- a/symbols.c
+++ b/symbols.c
@@ -10113,6 +10113,8 @@ dump_offset_table(char *spec, ulong makestruct)
 		OFFSET(device_private_device));
 	fprintf(fp, "      device_private_knode_bus: %ld\n",
 		OFFSET(device_private_knode_bus));
+	fprintf(fp, "    device_private_knode_class: %ld\n",
+		OFFSET(device_private_knode_class));
 	fprintf(fp, "                   gendisk_dev: %ld\n",
 		OFFSET(gendisk_dev));
 	fprintf(fp, "                  gendisk_kobj: %ld\n",
-- 
2.18.1




More information about the Crash-utility mailing list