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 <[email protected]>
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
[email protected]
https://www.redhat.com/mailman/listinfo/crash-utility