Re: introduce a new command to display the disk's information

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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

[Index of Archives]     [Fedora Development]     [Fedora Desktop]     [Fedora SELinux]     [Yosemite News]     [KDE Users]     [Fedora Tools]

 

Powered by Linux