Commit 837c7878 authored by Ben Woodard's avatar Ben Woodard Committed by Jens Axboe

[BLOCK] increase size of disk stat counters

The kernel's representation of the disk statistics uses the type unsigned
which is 32b on both 32b and 64b platforms.  Unfortunately, most system
tools that work with these numbers that are exported in /proc/diskstats
including iostat read these numbers into unsigned longs.  This works fine
on 32b platforms and when the number of IO transactions are small on 64b
platforms.  However, when the numbers wrap on 64b platforms & you read the
numbers into unsigned longs, and compare the numbers to previous readings,
then you get an unsigned representation of a negative number.  This looks
like a very large 64b number & gives you bizarre readouts in iostat:

ilc4: Device:    rrqm/s wrqm/s r/s    w/s  rsec/s  wsec/s    rkB/s wkB/s avgrq-sz avgqu-sz   await  svctm  %util
ilc4: sda        5.50   0.00   143.96 0.00 307496983987862656.00 0.00 153748491993931328.00     0.00 2136028725038430.00     7.94   55.12    5.59  80.42

Though fixing iostat in user space is possible, and a quick survey
indicates that several other similar tools also use unsigned longs when
processing /proc/diskstats.  Therefore, it seems like a better approach
would be to extend the length of the disk_stats structure on 64b
architectures to 64b.  The following patch does that.  It should not affect
the operation on 32b platforms.
Signed-off-by: default avatarBen Woodard <woodard@redhat.com>
Cc: Rick Lindsley <ricklind@us.ibm.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarJens Axboe <axboe@suse.de>
parent 4c5d0bbd
...@@ -454,8 +454,8 @@ static ssize_t disk_stats_read(struct gendisk * disk, char *page) ...@@ -454,8 +454,8 @@ static ssize_t disk_stats_read(struct gendisk * disk, char *page)
disk_round_stats(disk); disk_round_stats(disk);
preempt_enable(); preempt_enable();
return sprintf(page, return sprintf(page,
"%8u %8u %8llu %8u " "%8lu %8lu %8llu %8u "
"%8u %8u %8llu %8u " "%8lu %8lu %8llu %8u "
"%8u %8u %8u" "%8u %8u %8u"
"\n", "\n",
disk_stat_read(disk, ios[READ]), disk_stat_read(disk, ios[READ]),
...@@ -649,7 +649,7 @@ static int diskstats_show(struct seq_file *s, void *v) ...@@ -649,7 +649,7 @@ static int diskstats_show(struct seq_file *s, void *v)
preempt_disable(); preempt_disable();
disk_round_stats(gp); disk_round_stats(gp);
preempt_enable(); preempt_enable();
seq_printf(s, "%4d %4d %s %u %u %llu %u %u %u %llu %u %u %u %u\n", seq_printf(s, "%4d %4d %s %lu %lu %llu %u %lu %lu %llu %u %u %u %u\n",
gp->major, n + gp->first_minor, disk_name(gp, n, buf), gp->major, n + gp->first_minor, disk_name(gp, n, buf),
disk_stat_read(gp, ios[0]), disk_stat_read(gp, merges[0]), disk_stat_read(gp, ios[0]), disk_stat_read(gp, merges[0]),
(unsigned long long)disk_stat_read(gp, sectors[0]), (unsigned long long)disk_stat_read(gp, sectors[0]),
......
...@@ -89,12 +89,12 @@ struct hd_struct { ...@@ -89,12 +89,12 @@ struct hd_struct {
#define GENHD_FL_SUPPRESS_PARTITION_INFO 32 #define GENHD_FL_SUPPRESS_PARTITION_INFO 32
struct disk_stats { struct disk_stats {
unsigned sectors[2]; /* READs and WRITEs */ unsigned long sectors[2]; /* READs and WRITEs */
unsigned ios[2]; unsigned long ios[2];
unsigned merges[2]; unsigned long merges[2];
unsigned ticks[2]; unsigned long ticks[2];
unsigned io_ticks; unsigned long io_ticks;
unsigned time_in_queue; unsigned long time_in_queue;
}; };
struct gendisk { struct gendisk {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment