Fix failure of "dev -d|-D" options on Linux 6.4 and later kernels

Kernel commit 2df418cf4b72 ("driver core: class: remove subsystem
private pointer from struct class"), which is contained in Linux 6.4 and
later kernels, removed the class.p member for struct subsys_private.  As
a result, the "dev -d|-D" options fail with the following error.

  dev: invalid structure member offset: class_p
       FILE: dev.c  LINE: 4689  FUNCTION: init_iter()

Search the class_kset list for the subsys_private of block class to fix
this.

As a preparation, introduce get_subsys_private() function, which is
abstracted from the same search procedure in init_memory_block().

Signed-off-by: Kazuhito Hagio <k-hagio-ab@nec.com>
This commit is contained in:
Kazuhito Hagio 2023-05-16 08:59:50 +09:00
parent 040a56e9f9
commit 58c1816521
4 changed files with 64 additions and 35 deletions

1
defs.h
View File

@ -5521,6 +5521,7 @@ struct rb_node *rb_left(struct rb_node *, struct rb_node *);
struct rb_node *rb_next(struct rb_node *);
struct rb_node *rb_last(struct rb_root *);
long percpu_counter_sum_positive(ulong fbc);
ulong get_subsys_private(char *, char *);
/*
* symbols.c

20
dev.c
View File

@ -4686,9 +4686,16 @@ init_iter(struct iter *i)
} else {
/* kernel version > 2.6.27, klist */
unsigned long class_private_addr;
readmem(block_class_addr + OFFSET(class_p), KVADDR,
&class_private_addr, sizeof(class_private_addr),
"class.p", FAULT_ON_ERROR);
if (INVALID_MEMBER(class_p)) /* kernel version >= 6.4 */
class_private_addr = get_subsys_private("class_kset", "block");
else
readmem(block_class_addr + OFFSET(class_p), KVADDR,
&class_private_addr, sizeof(class_private_addr),
"class.p", FAULT_ON_ERROR);
if (!class_private_addr)
error(FATAL, "cannot determine subsys_private for block.\n");
if (VALID_STRUCT(class_private)) {
/* 2.6.27 < kernel version <= 2.6.37-rc2 */
@ -4823,6 +4830,13 @@ void diskio_init(void)
if (INVALID_MEMBER(class_devices))
MEMBER_OFFSET_INIT(class_devices, "class", "devices");
MEMBER_OFFSET_INIT(class_p, "class", "p");
if (INVALID_MEMBER(class_p)) {
MEMBER_OFFSET_INIT(kset_list, "kset", "list");
MEMBER_OFFSET_INIT(kset_kobj, "kset", "kobj");
MEMBER_OFFSET_INIT(kobject_name, "kobject", "name");
MEMBER_OFFSET_INIT(kobject_entry, "kobject", "entry");
MEMBER_OFFSET_INIT(subsys_private_subsys, "subsys_private", "subsys");
}
MEMBER_OFFSET_INIT(class_private_devices, "class_private",
"class_devices");
MEMBER_OFFSET_INIT(device_knode_class, "device", "knode_class");

View File

@ -17865,38 +17865,9 @@ init_memory_block(int *klistcnt, ulong **klistbuf)
* v6.3-rc1
* d2bf38c088e0 driver core: remove private pointer from struct bus_type
*/
if (INVALID_MEMBER(bus_type_p)) {
int i, cnt;
char buf[32];
ulong bus_kset, list, name;
BZERO(ld, sizeof(struct list_data));
get_symbol_data("bus_kset", sizeof(ulong), &bus_kset);
readmem(bus_kset + OFFSET(kset_list), KVADDR, &list,
sizeof(ulong), "bus_kset.list", FAULT_ON_ERROR);
ld->flags |= LIST_ALLOCATE;
ld->start = list;
ld->end = bus_kset + OFFSET(kset_list);
ld->list_head_offset = OFFSET(kobject_entry);
cnt = do_list(ld);
for (i = 0; i < cnt; i++) {
readmem(ld->list_ptr[i] + OFFSET(kobject_name), KVADDR, &name,
sizeof(ulong), "kobject.name", FAULT_ON_ERROR);
read_string(name, buf, sizeof(buf)-1);
if (CRASHDEBUG(1))
fprintf(fp, "kobject: %lx name: %s\n", ld->list_ptr[i], buf);
if (STREQ(buf, "memory")) {
/* entry is subsys_private.subsys.kobj. See bus_to_subsys(). */
private = ld->list_ptr[i] - OFFSET(kset_kobj)
- OFFSET(subsys_private_subsys);
break;
}
}
FREEBUF(ld->list_ptr);
} else {
if (INVALID_MEMBER(bus_type_p))
private = get_subsys_private("bus_kset", "memory");
else {
ulong memory_subsys = symbol_value("memory_subsys");
readmem(memory_subsys + OFFSET(bus_type_p), KVADDR, &private,
sizeof(void *), "memory_subsys.private", FAULT_ON_ERROR);

43
tools.c
View File

@ -6963,3 +6963,46 @@ percpu_counter_sum_positive(ulong fbc)
return (ret < 0) ? 0 : ret;
}
ulong
get_subsys_private(char *kset_name, char *target_name)
{
ulong kset_addr, kset_list, name_addr, private = 0;
struct list_data list_data, *ld;
char buf[32];
int i, cnt;
if (!symbol_exists(kset_name))
return 0;
ld = &list_data;
BZERO(ld, sizeof(struct list_data));
get_symbol_data(kset_name, sizeof(ulong), &kset_addr);
readmem(kset_addr + OFFSET(kset_list), KVADDR, &kset_list,
sizeof(ulong), "kset.list", FAULT_ON_ERROR);
ld->flags |= LIST_ALLOCATE;
ld->start = kset_list;
ld->end = kset_addr + OFFSET(kset_list);
ld->list_head_offset = OFFSET(kobject_entry);
cnt = do_list(ld);
for (i = 0; i < cnt; i++) {
readmem(ld->list_ptr[i] + OFFSET(kobject_name), KVADDR, &name_addr,
sizeof(ulong), "kobject.name", FAULT_ON_ERROR);
read_string(name_addr, buf, sizeof(buf)-1);
if (CRASHDEBUG(1))
fprintf(fp, "kobject: %lx name: %s\n", ld->list_ptr[i], buf);
if (STREQ(buf, target_name)) {
/* entry is subsys_private.subsys.kobj. See bus_to_subsys(). */
private = ld->list_ptr[i] - OFFSET(kset_kobj)
- OFFSET(subsys_private_subsys);
break;
}
}
FREEBUF(ld->list_ptr);
return private;
}