Hi, Dave At 01/21/2012 04:24 AM, Dave Anderson Wrote: > > > ----- Original Message ----- >> Hi, Dave >> >> When we investigate the problems of disk I/O, we want to get the disk's >> gendisk address and request queue's address easily, and the requests num >> is also important. >> >> Tha attached patch introduce a new command diskio to display such >> information. >> >> Thanks >> Wen Congyang > > Hello Wen, > > I built and tested this patch, and it certainly contains some useful > information. However, I do have a several suggestions. > > First, there's no need to make it a unique command. It would be > far more appropriate to make it a "dev" command option, which for > example, already shows gendisk structure addresses for each of the > block devices. > > So please move all of your functions from kernel.c to dev.c. > Then, for example, use "dev -d", and have cmd_dev() call your > command like this: > > while ((c = getopt(argcnt, args, "dpi")) != EOF) { > switch(c) > { > case 'd': > diskio_option(); > return; > ... > > Since all of the new offset_table and size_table entries are only > used by this command, you can avoid unnecessarily initializing > everything in kernel_init() by doing something like this: > > static void > diskio_option(void) > { > if (INVALID_MEMBER(class_devices)) { > MEMBER_OFFSET_INIT(class_devices, "class", "class_devices"); > if (INVALID_MEMBER(class_devices)) > MEMBER_OFFSET_INIT(class_devices, "class", "devices"); > MEMBER_OFFSET_INIT(class_p, "class", "p"); > MEMBER_OFFSET_INIT(class_private_devices, "class_private", > "class_devices"); > 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(gendisk_dev, "gendisk", "dev"); > if (INVALID_MEMBER(gendisk_dev)) > MEMBER_OFFSET_INIT(gendisk_dev, "gendisk", "__dev"); > MEMBER_OFFSET_INIT(gendisk_kobj, "gendisk", "kobj"); > 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(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"); > MEMBER_OFFSET_INIT(kobject_entry, "kobject", "entry"); > MEMBER_OFFSET_INIT(kset_list, "kset", "list"); > MEMBER_OFFSET_INIT(request_list_count, "request_list", "count"); > MEMBER_OFFSET_INIT(request_queue_in_flight, "request_queue", > "in_flight"); > MEMBER_OFFSET_INIT(request_queue_rq, "request_queue", "rq"); > MEMBER_OFFSET_INIT(subsys_private_klist_devices, "subsys_private", > "klist_devices"); > MEMBER_OFFSET_INIT(subsystem_kset, "subsystem", "kset"); > STRUCT_SIZE_INIT(subsystem, "subsystem"); > STRUCT_SIZE_INIT(class_private, "class_private"); > MEMBER_SIZE_INIT(rq_in_flight, "request_queue", "in_flight"); > MEMBER_SIZE_INIT(class_private_devices, "class_private", > "class_devices"); > } > > display_all_diskio(); > } > > Secondly, the whole READ/WRITE issue is confusing to the uninitiated > (like myself). After speaking with Jeff Moyer, we believe the output > of your command could be clarified. > > Your help page indicates: > > +" This command dumps I/O statistics of all disks:", > +" TOTAL: The total requests that have not been ended", > +" READ: The total read requests that have not been ended", > +" WRITE: The total write requests that have not been ended", > +" DRV: The total requests that have been in the driver, but not end", > +"", > +" Note: some kernel does not contain read/write requests, and the command", > +" will output '-----'" > +"\nEXAMPLES", > +" %s> diskio", > +" MAJOR GENDISK NAME RUQUEST QUEUE TOTAL READ WRITE DRV", > +" 008 0xe00000010773ea80 sda 0x3000000109c9fbf0 12 0 12 0", > +" 008 0xe00000010773e680 sdb 0x3000000109c9f8a0 2 2 0 0", > +" 008 0xe000000107781d80 sdc 0x300000010c268050 6 0 6 6", > +" 008 0xe00000010773e080 sdd 0x300000010c26bbf0 0 0 0 0", > +" 008 0xe00000010773dc80 sde 0x300000010c3dd780 0 0 0 0", > +NULL > > As Jeff explained to me, this is how it works: > > (1) In older kernels, this enum did not exist: > > enum { > BLK_RW_ASYNC = 0, > BLK_RW_SYNC = 1, > }; > > and in that case, the request_list.count[2] values are the > READ/WRITE values, as you show in the help page example above. > > (2) In newer kernels, the enum does exist, and the meaning of the > request_list.count[2] values are ASYNC/SYNC requests. In that > case, you show "-----" under the READ and WRITE columns, which > I found *very* confusing. > > What Jeff Moyer suggested is that -- in the case of new kernels -- you > should alternatively show the counts with ASYNC and SYNC columns like > this: > > MAJOR GENDISK NAME REQUEST QUEUE TOTAL ASYNC SYNC DRV", > ... > > And the READ/WRITE vs. ASYNC/SYNC output display difference should be > referenced in the help page output. > > Third, a minor nit -- note that you misspelled it as "RUQUEST" both in > the command and in the help page. Also, it appears that you used an IA64 as > the example, given the GENDISK addresses. But aren't the REQUEST QUEUE > addresses below beginning with "0x300..." user-space addresses for IA64? > > +" MAJOR GENDISK NAME RUQUEST QUEUE TOTAL READ WRITE DRV", > +" 008 0xe00000010773ea80 sda 0x3000000109c9fbf0 12 0 12 0", > +" 008 0xe00000010773e680 sdb 0x3000000109c9f8a0 2 2 0 0", > +" 008 0xe000000107781d80 sdc 0x300000010c268050 6 0 6 6", > +" 008 0xe00000010773e080 sdd 0x300000010c26bbf0 0 0 0 0", > +" 008 0xe00000010773dc80 sde 0x300000010c3dd780 0 0 0 0", > > In any case, can you change it to use either x86_64 or x86 as an example? > > Fourth, in testing this with a 2.6.25 kernel, the command hangs: > > crash> dev -d > MAJOR GENDISK NAME REQUEST QUEUE TOTAL READ WRITE DRV > 2 0xffff81012d8a5000 fd0 0xffff81012dc053c0 0 0 0 0 > 22 0xffff81012dc6b000 hdc 0xffff81012d8ae340 0 0 0 0 > 8 0xffff81012dd71000 sda 0xffff81012d8af040 0 0 0 0 > < hangs here forever > > > I'm not absolutely sure, but if I hit CTRL-C under gdb, it seems that it's > spinning in next_disk_list() in that "goto again" loop? > > Fifth, I tried it on a much older RHEL3 kernel, which shows: > > crash> dev -d > dev: invalid request_queue.in_flight's size > crash> > > It's not really invalid size, but it's more the case that you > don't support that old a kernel version. In that case, instead > of doing this: > > error(FATAL, "invalid request_queue.in_flight's size\n"); > > you should do this instead: > > option_not_supported('d'); > > And finally, whenever adding fields to the offset_table or size_table, > please display their values in dump_offset_table() for the "help -o" > command. I have updated the patch. Thanks Wen Congyang > > Thanks, > Dave > > > > >
>From 5ad4c02d59b5a0655d972cc7b18c28c26e5f1434 Mon Sep 17 00:00:00 2001 From: Wen Congyang <wency@xxxxxxxxxxxxxx> Date: Mon, 30 Jan 2012 13:30:24 +0800 Subject: [PATCH] display all disk I/O statistics --- defs.h | 25 ++++ dev.c | 473 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- help.c | 20 +++- symbols.c | 49 +++++++ 4 files changed, 565 insertions(+), 2 deletions(-) diff --git a/defs.h b/defs.h index 82d51e5..b5ebadd 100644 --- a/defs.h +++ b/defs.h @@ -1631,6 +1631,27 @@ struct offset_table { /* stash of commonly-used offsets */ long sched_entity_my_q; long sched_entity_on_rq; long task_struct_on_rq; + + long class_devices; + long class_p; + long class_private_devices; + long device_knode_class; + long device_node; + long gendisk_dev; + long gendisk_kobj; + long gendisk_part0; + long gendisk_queue; + long hd_struct_dev; + long klist_k_list; + long klist_node_n_klist; + long klist_node_n_node; + long kobject_entry; + long kset_list; + long request_list_count; + long request_queue_in_flight; + long request_queue_rq; + long subsys_private_klist_devices; + long subsystem_kset; }; struct size_table { /* stash of commonly-used sizes */ @@ -1752,6 +1773,10 @@ struct size_table { /* stash of commonly-used sizes */ long s390_stack_frame; long percpu_data; long sched_entity; + long subsystem; + long class_private; + long rq_in_flight; + long class_private_devices; }; struct array_table { diff --git a/dev.c b/dev.c index d96cd19..fc59e47 100644 --- a/dev.c +++ b/dev.c @@ -30,6 +30,8 @@ static void do_resource_list(ulong, char *, int); static const char *pci_strclass (uint, char *); static const char *pci_strvendor(uint, char *); static const char *pci_strdev(uint, uint, char *); + +static void diskio_option(void); static struct dev_table { ulong flags; @@ -90,9 +92,12 @@ cmd_dev(void) flags = 0; - while ((c = getopt(argcnt, args, "pi")) != EOF) { + while ((c = getopt(argcnt, args, "dpi")) != EOF) { switch(c) { + case 'd': + diskio_option(); + return; case 'i': if (machine_type("S390X")) option_not_supported(c); @@ -3580,3 +3585,469 @@ pci_strdev(unsigned int vendor, unsigned int device, char *buf) return buf; } } + +/* + * If the disk's name is started with these strings, we will skip it and do not + * display its statistics. + */ +static char *skipped_disk_name[] = { + "ram", + "loop", + NULL +}; + +static int is_skipped_disk(char *name) +{ + char **p = skipped_disk_name; + + while (*p) { + if (strncmp(name, *p, strlen(*p)) == 0) + return TRUE; + p++; + } + + return FALSE; +} + +struct diskio { + int read; + int write; +}; + +struct iter { + /* If the kernel uses klist, the address should be klist.k_list */ + long head_address; + long current_address; + long type_address; /* the address of symbol "disk_type" */ + + /* + * If it is true, it means request_list.count[2] contains async/sync + * requests. + */ + int sync_count; + int diskname_len; + + unsigned long (*next_disk)(struct iter *); + + /* + * The argument is the address of request_queue, and the function + * returns the total requests in the driver(not ended) + */ + unsigned int (*get_in_flight)(unsigned long); + + /* + * this function reads request_list.count[2], and the first argument + * is the address of request_queue. + */ + void (*get_diskio)(unsigned long , struct diskio *); + + /* + * check if device.type == &disk_type + * + * old kernel(version <= 2.6.24) does not have the symbol "disk_type", + * and this callback should be null. + */ + int (*match)(struct iter *, unsigned long); + + /* + * If the kernel uses list, the argument is the address of list_head, + * otherwise, the argument is the address of klist_node. + */ + unsigned long (*get_gendisk)(unsigned long); +}; + +/* kernel version <= 2.6.24 */ +static unsigned long get_gendisk_1(unsigned long entry) +{ + return entry - OFFSET(kobject_entry) - OFFSET(gendisk_kobj); +} + +/* 2.6.24 < kernel version <= 2.6.27 */ +static unsigned long get_gendisk_2(unsigned long entry) +{ + return entry - OFFSET(device_node) - OFFSET(gendisk_dev); +} + +/* kernel version > 2.6.27 && struct gendisk contains dev/__dev */ +static unsigned long get_gendisk_3(unsigned long entry) +{ + return entry - OFFSET(device_knode_class) - OFFSET(gendisk_dev); +} + +/* kernel version > 2.6.27 && struct gendisk does not contain dev/__dev */ +static unsigned long get_gendisk_4(unsigned long entry) +{ + return entry - OFFSET(device_knode_class) - 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) +{ + unsigned long device_address; + unsigned long device_type; + + device_address = entry - OFFSET(device_node); + readmem(device_address + OFFSET(device_type), KVADDR, &device_type, + sizeof(device_type), "device.type", FAULT_ON_ERROR); + if (device_type != i->type_address) + return FALSE; + + return TRUE; +} + +/* kernel version > 2.6.27 */ +static int match_klist(struct iter *i, unsigned long entry) +{ + unsigned long device_address; + unsigned long device_type; + + device_address = entry - OFFSET(device_knode_class); + readmem(device_address + OFFSET(device_type), KVADDR, &device_type, + sizeof(device_type), "device.type", FAULT_ON_ERROR); + if (device_type != i->type_address) + return FALSE; + + return TRUE; +} + +/* old kernel(version <= 2.6.27): list */ +static unsigned long next_disk_list(struct iter *i) +{ + unsigned long list_head_address, next_address; + + if (i->current_address) { + list_head_address = i->current_address; + } else { + list_head_address = i->head_address; + } + +again: + /* read list_head.next */ + readmem(list_head_address + OFFSET(list_head_next), KVADDR, + &next_address, sizeof(next_address), "list_head.next", + FAULT_ON_ERROR); + + if (next_address == i->head_address) + return 0; + + if (i->match && !i->match(i, next_address)) { + list_head_address = next_address; + goto again; + } + + i->current_address = next_address; + return i->get_gendisk(next_address); +} + +/* new kernel(version > 2.6.27): klist */ +static unsigned long next_disk_klist(struct iter* i) +{ + unsigned long klist_node_address, list_head_address, next_address; + unsigned long n_klist; + + if (i->current_address) { + list_head_address = i->current_address; + } else { + list_head_address = i->head_address; + } + +again: + /* read list_head.next */ + readmem(list_head_address + OFFSET(list_head_next), KVADDR, + &next_address, sizeof(next_address), "list_head.next", + FAULT_ON_ERROR); + + /* skip dead klist_node */ + while(next_address != i->head_address) { + klist_node_address = next_address - OFFSET(klist_node_n_node); + readmem(klist_node_address + OFFSET(klist_node_n_klist), KVADDR, + &n_klist, sizeof(n_klist), "klist_node.n_klist", + FAULT_ON_ERROR); + if (!(n_klist & 1)) + break; + + /* the klist_node is dead, skip to next klist_node */ + readmem(next_address + OFFSET(list_head_next), KVADDR, + &next_address, sizeof(next_address), "list_head.next", + FAULT_ON_ERROR); + } + + if (next_address == i->head_address) + return 0; + + if (i->match && !i->match(i, klist_node_address)) { + list_head_address = next_address; + goto again; + } + + i->current_address = next_address; + return i->get_gendisk(klist_node_address); +} + +/* read request_queue.rq.count[2] */ +static void get_diskio_1(unsigned long rq, struct diskio *io) +{ + int count[2]; + + 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]; +} + +/* request_queue.in_flight contains total requests */ +static unsigned int get_in_flight_1(unsigned long rq) +{ + unsigned int in_flight; + + readmem(rq+ OFFSET(request_queue_in_flight), KVADDR, &in_flight, + sizeof(uint), "request_queue.in_flight", FAULT_ON_ERROR); + return in_flight; +} + +/* request_queue.in_flight[2] contains read/write requests */ +static unsigned int get_in_flight_2(unsigned long rq) +{ + unsigned int in_flight[2]; + + readmem(rq+ OFFSET(request_queue_in_flight), KVADDR, in_flight, + sizeof(uint) * 2, "request_queue.in_flight", FAULT_ON_ERROR); + return in_flight[0] + in_flight[1]; +} + +static void init_iter(struct iter *i) +{ + ARRAY_LENGTH_INIT(i->diskname_len, gendisk.disk_name, + "gendisk.disk_name", NULL, sizeof(char)); + if (i->diskname_len < 0 || i->diskname_len > BUFSIZE) { + option_not_supported('d'); + return; + } + + i->current_address = 0; + + /* check whether BLK_RW_SYNC exists */ + i->sync_count = + get_symbol_type("BLK_RW_SYNC", NULL, NULL) == TYPE_CODE_ENUM; + + if (SIZE(rq_in_flight) == sizeof(int)) { + 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; + + if (symbol_exists("block_subsys") || symbol_exists("block_kset")) { + /* kernel version <= 2.6.24 */ + unsigned long block_subsys_addr; + + if (symbol_exists("block_subsys")) + block_subsys_addr = symbol_value("block_subsys"); + else + block_subsys_addr = symbol_value("block_kset"); + if (VALID_STRUCT(subsystem)) + i->head_address = block_subsys_addr + + OFFSET(subsystem_kset) + OFFSET(kset_list); + else + i->head_address = block_subsys_addr + OFFSET(kset_list); + i->type_address = 0; + i->next_disk = next_disk_list; + i->match = NULL; + i->get_gendisk = get_gendisk_1; + } else if (symbol_exists("block_class")) { + unsigned long block_class_addr = symbol_value("block_class"); + + i->type_address = symbol_value("disk_type"); + if (VALID_MEMBER(class_devices) || + (VALID_MEMBER(class_private_devices) && + SIZE(class_private_devices) == SIZE(list_head))) { + /* 2.6.24 < kernel version <= 2.6.27, list */ + if (!VALID_STRUCT(class_private)) { + /* 2.6.24 < kernel version <= 2.6.26 */ + i->head_address = block_class_addr + + OFFSET(class_devices); + } else { + /* kernel version is 2.6.27 */ + 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); + i->head_address = class_private_addr + + OFFSET(class_private_devices); + } + i->next_disk = next_disk_list; + i->match = match_list; + i->get_gendisk = get_gendisk_2; + } 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 (VALID_STRUCT(class_private)) { + /* 2.6.27 < kernel version <= 2.6.37-rc2 */ + i->head_address = class_private_addr + + OFFSET(class_private_devices); + } else { + /* kernel version > 2.6.37-rc2 */ + i->head_address = class_private_addr + + OFFSET(subsys_private_klist_devices); + } + i->head_address += OFFSET(klist_k_list); + i->next_disk = next_disk_klist; + i->match = match_klist; + if (VALID_MEMBER(gendisk_dev)) + i->get_gendisk = get_gendisk_3; + else + i->get_gendisk = get_gendisk_4; + } + } else { + option_not_supported('d'); + return; + } +} + +static void display_one_diskio(struct iter *i, unsigned long gendisk) +{ + char disk_name[BUFSIZE + 1]; + char buf0[BUFSIZE]; + char buf1[BUFSIZE]; + char buf2[BUFSIZE]; + char buf3[BUFSIZE]; + char buf4[BUFSIZE]; + char buf5[BUFSIZE]; + int major; + unsigned long queue_addr; + unsigned int in_flight; + struct diskio io; + + memset(disk_name, 0, BUFSIZE + 1); + readmem(gendisk + OFFSET(gendisk_disk_name), KVADDR, disk_name, + i->diskname_len, "gen_disk.disk_name", FAULT_ON_ERROR); + if (is_skipped_disk(disk_name)) + return; + + readmem(gendisk + OFFSET(gendisk_queue), KVADDR, &queue_addr, + 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); + in_flight = i->get_in_flight(queue_addr); + + fprintf(fp, "%s%s0x%s%s%s%s0x%s%s%5d%s%s%s%s%s%5u\n", + mkstring(buf0, 5, RJUST|INT_DEC, (char *)(unsigned long)major), + space(MINSPACE), + mkstring(buf1, VADDR_PRLEN, LJUST|LONG_HEX, (char *)gendisk), + space(MINSPACE), + mkstring(buf2, 4, RJUST, disk_name), + space(MINSPACE), + mkstring(buf3, VADDR_PRLEN <= 11 ? 11 : VADDR_PRLEN, + LJUST|LONG_HEX, (char *)queue_addr), + space(MINSPACE), + io.read + io.write, + space(MINSPACE), + mkstring(buf4, 5, RJUST|INT_DEC, + (char *)(unsigned long)io.read), + space(MINSPACE), + mkstring(buf5, 5, RJUST|INT_DEC, + (char *)(unsigned long)io.write), + space(MINSPACE), + in_flight); +} + +static void display_all_diskio(void) +{ + struct iter i; + unsigned long gendisk; + char buf0[BUFSIZE]; + char buf1[BUFSIZE]; + char buf2[BUFSIZE]; + char buf3[BUFSIZE]; + char buf4[BUFSIZE]; + char buf5[BUFSIZE]; + + init_iter(&i); + + fprintf(fp, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", + "MAJOR", + space(MINSPACE), + mkstring(buf0, VADDR_PRLEN + 2, LJUST, "GENDISK"), + space(MINSPACE), + "NAME", + space(MINSPACE), + mkstring(buf1, VADDR_PRLEN <= 11 ? 13 : VADDR_PRLEN + 2, LJUST, + "REQUEST QUEUE"), + space(MINSPACE), + mkstring(buf2, 5, RJUST, "TOTAL"), + space(MINSPACE), + i.sync_count ? mkstring(buf3, 5, RJUST, "ASYNC") : + mkstring(buf3, 5, RJUST, "READ"), + space(MINSPACE), + i.sync_count ? mkstring(buf4, 5, RJUST, "SYNC") : + mkstring(buf4, 5, RJUST, "WRITE"), + space(MINSPACE), + mkstring(buf5, 5, RJUST, "DRV")); + + while((gendisk = i.next_disk(&i)) != 0) { + display_one_diskio(&i, gendisk); + } +} + +static void diskio_init(void) +{ + static int initialized = 0; + + if (initialized) + return; + + initialized = 1; + + MEMBER_OFFSET_INIT(class_devices, "class", "class_devices"); + if (INVALID_MEMBER(class_devices)) + MEMBER_OFFSET_INIT(class_devices, "class", "devices"); + MEMBER_OFFSET_INIT(class_p, "class", "p"); + MEMBER_OFFSET_INIT(class_private_devices, "class_private", + "class_devices"); + 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(gendisk_dev, "gendisk", "dev"); + if (INVALID_MEMBER(gendisk_dev)) + MEMBER_OFFSET_INIT(gendisk_dev, "gendisk", "__dev"); + MEMBER_OFFSET_INIT(gendisk_kobj, "gendisk", "kobj"); + 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(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"); + MEMBER_OFFSET_INIT(kobject_entry, "kobject", "entry"); + MEMBER_OFFSET_INIT(kset_list, "kset", "list"); + MEMBER_OFFSET_INIT(request_list_count, "request_list", "count"); + MEMBER_OFFSET_INIT(request_queue_in_flight, "request_queue", + "in_flight"); + MEMBER_OFFSET_INIT(request_queue_rq, "request_queue", "rq"); + MEMBER_OFFSET_INIT(subsys_private_klist_devices, "subsys_private", + "klist_devices"); + MEMBER_OFFSET_INIT(subsystem_kset, "subsystem", "kset"); + STRUCT_SIZE_INIT(subsystem, "subsystem"); + STRUCT_SIZE_INIT(class_private, "class_private"); + MEMBER_SIZE_INIT(rq_in_flight, "request_queue", "in_flight"); + MEMBER_SIZE_INIT(class_private_devices, "class_private", + "class_devices"); +} + +static void diskio_option(void) +{ + diskio_init(); + display_all_diskio(); +} diff --git a/help.c b/help.c index adaaea7..82f5b27 100644 --- a/help.c +++ b/help.c @@ -2190,11 +2190,20 @@ NULL char *help_dev[] = { "dev", "device data", -"[-i | -p]", +"[-i | -p | -d]", " If no argument is entered, this command dumps character and block", " device data.\n", " -i display I/O port usage; on 2.4 kernels, also display I/O memory usage.", " -p display PCI device data.", +" -d display disk I/O statistics", +" TOTAL: The total requests that have not been ended", +" READ: The total read requests that have not been ended", +" WRITE: The total write requests that have not been ended", +" SYNC: The total sync requests that have not been ended", +" ASYNC: The total async requests that have not been ended", +" DRV: The total requests that have been in the driver, but not end", +" Note: it will output READ/WRITE on old kernel, and will output SYNC/ASYNC", +" on new kernel.", "\nEXAMPLES", " Display character and block device data:\n", " %s> dev", @@ -2318,6 +2327,15 @@ char *help_dev[] = { " c00040a0 fee00000-fee0ffff reserved", " c00040c0 ffe00000-ffffffff reserved", +"\n disk I/O statistics", +" %s> dev -d", +" MAJOR GENDISK NAME REQUEST QUEUE TOTAL READ WRITE DRV", +" 2 0xffff81012d8a5000 fd0 0xffff81012dc053c0 12 0 12 0", +" 22 0xffff81012dc6b000 hdc 0xffff81012d8ae340 2 2 0 0", +" 8 0xffff81012dd71000 sda 0xffff81012d8af040 6 0 6 6", +" 8 0xffff81012dc77000 sdb 0xffff81012d8b5740 0 0 0 0", +" 8 0xffff81012d8d0c00 sdc 0xffff81012d8ae9c0 0 0 0 0", + NULL }; diff --git a/symbols.c b/symbols.c index a68b585..cee2927 100644 --- a/symbols.c +++ b/symbols.c @@ -8594,6 +8594,47 @@ dump_offset_table(char *spec, ulong makestruct) fprintf(fp, " unwind_idx_insn: %ld\n", OFFSET(unwind_idx_insn)); + fprintf(fp, " class_devices: %ld\n", + OFFSET(class_devices)); + fprintf(fp, " class_p: %ld\n", + OFFSET(class_p)); + fprintf(fp, " class_private_devices: %ld\n", + OFFSET(class_private_devices)); + fprintf(fp, " device_knode_class: %ld\n", + OFFSET(device_knode_class)); + fprintf(fp, " device_node: %ld\n", + OFFSET(device_node)); + fprintf(fp, " gendisk_dev: %ld\n", + OFFSET(gendisk_dev)); + fprintf(fp, " gendisk_kobj: %ld\n", + OFFSET(gendisk_kobj)); + fprintf(fp, " gendisk_part0: %ld\n", + OFFSET(gendisk_part0)); + fprintf(fp, " gendisk_queue: %ld\n", + OFFSET(gendisk_queue)); + fprintf(fp, " hd_struct_dev: %ld\n", + OFFSET(hd_struct_dev)); + fprintf(fp, " klist_k_list: %ld\n", + OFFSET(klist_k_list)); + fprintf(fp, " klist_node_n_klist: %ld\n", + OFFSET(klist_node_n_klist)); + fprintf(fp, " klist_node_n_node: %ld\n", + OFFSET(klist_node_n_node)); + fprintf(fp, " kobject_entry: %ld\n", + OFFSET(kobject_entry)); + fprintf(fp, " kset_list: %ld\n", + OFFSET(kset_list)); + fprintf(fp, " request_list_count: %ld\n", + OFFSET(request_list_count)); + fprintf(fp, " request_queue_in_flight: %ld\n", + OFFSET(request_queue_in_flight)); + fprintf(fp, " request_queue_rq: %ld\n", + OFFSET(request_queue_rq)); + fprintf(fp, " subsys_private_klist_devices: %ld\n", + OFFSET(subsys_private_klist_devices)); + fprintf(fp, " subsystem_kset: %ld\n", + OFFSET(subsystem_kset)); + fprintf(fp, "\n size_table:\n"); fprintf(fp, " page: %ld\n", SIZE(page)); fprintf(fp, " page_flags: %ld\n", SIZE(page_flags)); @@ -8783,6 +8824,14 @@ dump_offset_table(char *spec, ulong makestruct) SIZE(percpu_data)); fprintf(fp, " sched_entity: %ld\n", SIZE(sched_entity)); + fprintf(fp, " subsystem: %ld\n", + SIZE(subsystem)); + fprintf(fp, " class_private: %ld\n", + SIZE(class_private)); + fprintf(fp, " rq_in_flight: %ld\n", + SIZE(rq_in_flight)); + fprintf(fp, " class_private_devices: %ld\n", + SIZE(class_private_devices)); fprintf(fp, "\n array_table:\n"); /* -- 1.7.1
-- Crash-utility mailing list Crash-utility@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/crash-utility