From b922a2c8aeecfe8b1033ba419b475dfd4e51ef16 Mon Sep 17 00:00:00 2001 From: Kazuhito Hagio Date: Tue, 19 Jan 2021 15:03:39 +0900 Subject: [PATCH 10/13] Fix "dev -d" option on Linux 5.11-rc1 and later kernels Fix the "dev -d" option on Linux 5.11-rc1 and later kernels that contains commit 0d02129e76edf91cf04fabf1efbc3a9a1f1d729a ("block: merge struct block_device and struct hd_struct"). Without the patch, the option fails with the error message "dev: invalid structure member offset: hd_struct_dev". Signed-off-by: Kazuhito Hagio Signed-off-by: Lianbo Jiang --- defs.h | 2 ++ dev.c | 29 +++++++++++++++++++++++++---- symbols.c | 4 ++++ 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/defs.h b/defs.h index e468b1d99fcf..ffbe73bfb508 100644 --- a/defs.h +++ b/defs.h @@ -2128,6 +2128,8 @@ struct offset_table { /* stash of commonly-used offsets */ long prb_data_ring_size_bits; long prb_data_ring_data; long atomic_long_t_counter; + long block_device_bd_device; + long block_device_bd_stats; }; struct size_table { /* stash of commonly-used sizes */ diff --git a/dev.c b/dev.c index 56e84ab9007c..effe789f38d8 100644 --- a/dev.c +++ b/dev.c @@ -4067,13 +4067,22 @@ get_gendisk_5(unsigned long entry) { unsigned long device_address; unsigned long device_private_address; + unsigned long gendisk; 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); + if (VALID_MEMBER(hd_struct_dev)) + return device_address - OFFSET(hd_struct_dev) - OFFSET(gendisk_part0); + + /* kernel version >= 5.11 */ + readmem(device_address - OFFSET(block_device_bd_device) + + OFFSET(block_device_bd_disk), KVADDR, &gendisk, + sizeof(ulong), "block_device.bd_disk", FAULT_ON_ERROR); + + return gendisk; } /* 2.6.24 < kernel version <= 2.6.27 */ @@ -4290,9 +4299,19 @@ get_diskio_1(unsigned long rq, unsigned long gendisk, struct diskio *io) 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); + if (VALID_MEMBER(hd_struct_dkstats)) + readmem(gendisk + OFFSET(gendisk_part0) + + OFFSET(hd_struct_dkstats), KVADDR, &dkstats, + sizeof(ulong), "gendisk.part0.dkstats", FAULT_ON_ERROR); + else { /* kernel version >= 5.11 */ + ulong block_device; + readmem(gendisk + OFFSET(gendisk_part0), KVADDR, &block_device, + sizeof(ulong), "gendisk.part0", FAULT_ON_ERROR); + readmem(block_device + OFFSET(block_device_bd_stats), KVADDR, + &dkstats, sizeof(ulong), "block_device.bd_stats", + FAULT_ON_ERROR); + } + get_one_diskio_from_dkstats(dkstats, io_counts); io->read = io_counts[0]; @@ -4549,6 +4568,8 @@ void diskio_init(void) 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(block_device_bd_device, "block_device", "bd_device"); + MEMBER_OFFSET_INIT(block_device_bd_stats, "block_device", "bd_stats"); 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"); diff --git a/symbols.c b/symbols.c index a51078d58e6b..ed5f731fa1b3 100644 --- a/symbols.c +++ b/symbols.c @@ -9291,6 +9291,10 @@ dump_offset_table(char *spec, ulong makestruct) OFFSET(block_device_bd_list)); fprintf(fp, " block_device_bd_disk: %ld\n", OFFSET(block_device_bd_disk)); + fprintf(fp, " block_device_bd_device: %ld\n", + OFFSET(block_device_bd_device)); + fprintf(fp, " block_device_bd_stats: %ld\n", + OFFSET(block_device_bd_stats)); fprintf(fp, " address_space_nrpages: %ld\n", OFFSET(address_space_nrpages)); fprintf(fp, " address_space_page_tree: %ld\n", -- 2.17.1