Hello *,
I made a fix by sorting the read lines from /proc/diskstats.
Diff:
703c703
< char line[256], dev_name[MAX_NAME_LEN], dev_name2[MAX_NAME_LEN];
---
> char line[256], dev_name[MAX_NAME_LEN];
713,717d712
< char *lines[256]; /* Array of 256 pointers to line-strings */
< int line_len;
< int line_nb=0; /* will contain the line (device) count */
< int l_c, l_c2;
< char *tmp;
724,725c719
< /* /proc/diskstats contains an unordered list of devices */
< if ((fp = fopen(DISKSTATS, "r")) == NULL)
---
> if ((fp = fopen(DISKSTATS, "r")) == NULL)
727,733d720
< while (fgets(line, sizeof(line), fp) != NULL && line_nb < 256) {
< line_len=strlen(line);
< lines[line_nb]=malloc(line_len+1); /* Make room for the
terminating \0 */
< memcpy(lines[line_nb], line, line_len+1); /* memcpy is faster
than strcpy */
< line_nb++;
< }
< fclose(fp);
735,754c722,723
< /* Sort device list */
< for (l_c=0; l_c < line_nb-1; l_c++)
< {
< sscanf(lines[l_c], "%u %u %s", &major, &minor, dev_name);
< for (l_c2=l_c+1; l_c2 < line_nb; l_c2++)
< {
< sscanf(lines[l_c2], "%u %u %s", &major, &minor, dev_name2);
< if (strncmp(dev_name, dev_name2, sizeof(line)) > 0) { //
swap places
< tmp=lines[l_c];
< lines[l_c]=lines[l_c2];
< lines[l_c2]=tmp;
< l_c--; /* walk thru it again */
< break;
< }
< }
< }
<
< /* Walk through device list */
< for (l_c=0; l_c < line_nb; l_c++)
< {
---
> while (fgets(line, sizeof(line), fp) != NULL) {
>
756c725
< i = sscanf(lines[l_c], "%u %u %s %lu %lu %lu %lu %lu %lu %lu %u
%u %u %u %lu %lu %lu %lu",
---
> i = sscanf(line, "%u %u %s %lu %lu %lu %lu %lu %lu %lu %u %u %u
> %u %lu %lu %lu %lu",
828,831c797
<
< /* Free the lines array */
< for (l_c=0; l_c < line_nb; l_c++)
< free(lines[l_c]);
---
> fclose(fp);
Maybe more readable: the whole function…
/*
***************************************************************************
* Read stats from /proc/diskstats.
*
* IN:
* @curr Index in array for current sample statistics.
***************************************************************************
*/
void read_diskstats_stat(int curr)
{
FILE *fp;
char line[256], dev_name[MAX_NAME_LEN], dev_name2[MAX_NAME_LEN];
char *dm_name;
struct io_stats sdev;
int i;
unsigned int ios_pgr, tot_ticks, rq_ticks, wr_ticks;
unsigned long rd_ios, rd_merges_or_rd_sec, rd_ticks_or_wr_sec, wr_ios;
unsigned long wr_merges, rd_sec_or_wr_ios, wr_sec;
unsigned long dc_ios, dc_merges, dc_sec, dc_ticks;
char *ioc_dname;
unsigned int major, minor;
char *lines[256]; /* Array of 256 pointers to line-strings */
int line_len;
int line_nb=0; /* will contain the line (device) count */
int l_c, l_c2;
char *tmp;
memset(&sdev, 0, sizeof(struct io_stats));
/* Every I/O device entry is potentially unregistered */
set_entries_unregistered(iodev_nr, st_hdr_iodev);
/* /proc/diskstats contains an unordered list of devices */
if ((fp = fopen(DISKSTATS, "r")) == NULL)
return;
while (fgets(line, sizeof(line), fp) != NULL && line_nb < 256) {
line_len=strlen(line);
lines[line_nb]=malloc(line_len+1); /* Make room for the
terminating \0 */
memcpy(lines[line_nb], line, line_len+1); /* memcpy is faster
than strcpy */
line_nb++;
}
fclose(fp);
/* Sort device list */
for (l_c=0; l_c < line_nb-1; l_c++)
{
sscanf(lines[l_c], "%u %u %s", &major, &minor, dev_name);
for (l_c2=l_c+1; l_c2 < line_nb; l_c2++)
{
sscanf(lines[l_c2], "%u %u %s", &major, &minor, dev_name2);
if (strncmp(dev_name, dev_name2, sizeof(line)) > 0) { // swap
places
tmp=lines[l_c];
lines[l_c]=lines[l_c2];
lines[l_c2]=tmp;
l_c--; /* walk thru it again */
break;
}
}
}
/* Walk through device list */
for (l_c=0; l_c < line_nb; l_c++)
{
/* major minor name rio rmerge rsect ruse wio wmerge wsect wuse
running use aveq dcio dcmerge dcsect dcuse*/
i = sscanf(lines[l_c], "%u %u %s %lu %lu %lu %lu %lu %lu %lu %u
%u %u %u %lu %lu %lu %lu",
&major, &minor, dev_name,
&rd_ios, &rd_merges_or_rd_sec, &rd_sec_or_wr_ios,
&rd_ticks_or_wr_sec,
&wr_ios, &wr_merges, &wr_sec, &wr_ticks, &ios_pgr,
&tot_ticks, &rq_ticks,
&dc_ios, &dc_merges, &dc_sec, &dc_ticks);
if (i >= 14) {
/* Device or partition */
if (!dlist_idx && !DISPLAY_PARTITIONS(flags) &&
!is_device(dev_name, ACCEPT_VIRTUAL_DEVICES))
continue;
sdev.rd_ios = rd_ios;
sdev.rd_merges = rd_merges_or_rd_sec;
sdev.rd_sectors = rd_sec_or_wr_ios;
sdev.rd_ticks = (unsigned int) rd_ticks_or_wr_sec;
sdev.wr_ios = wr_ios;
sdev.wr_merges = wr_merges;
sdev.wr_sectors = wr_sec;
sdev.wr_ticks = wr_ticks;
sdev.ios_pgr = ios_pgr;
sdev.tot_ticks = tot_ticks;
sdev.rq_ticks = rq_ticks;
if (i == 18) {
/* Discard I/O */
sdev.dc_ios = dc_ios;
sdev.dc_merges = dc_merges;
sdev.dc_sectors = dc_sec;
sdev.dc_ticks = dc_ticks;
}
}
else if (i == 7) {
/* Partition without extended statistics */
if (DISPLAY_EXTENDED(flags) ||
(!dlist_idx && !DISPLAY_PARTITIONS(flags)))
continue;
sdev.rd_ios = rd_ios;
sdev.rd_sectors = rd_merges_or_rd_sec;
sdev.wr_ios = rd_sec_or_wr_ios;
sdev.wr_sectors = rd_ticks_or_wr_sec;
}
else
/* Unknown entry: Ignore it */
continue;
if ((ioc_dname = ioc_name(major, minor)) != NULL) {
if (strcmp(dev_name, ioc_dname) && strcmp(ioc_dname,
K_NODEV)) {
/*
* No match: Use name generated from
sysstat.ioconf data
* (if different from "nodev") works around
known issues
* with EMC PowerPath.
*/
strncpy(dev_name, ioc_dname, MAX_NAME_LEN - 1);
dev_name[MAX_NAME_LEN - 1] = '\0';
}
}
if ((DISPLAY_DEVMAP_NAME(flags)) && (major == dm_major)) {
/*
* If the device is a device mapper device, try to get
its
* assigned name of its logical device.
*/
dm_name = transform_devmapname(major, minor);
if (dm_name) {
strncpy(dev_name, dm_name, MAX_NAME_LEN - 1);
dev_name[MAX_NAME_LEN - 1] = '\0';
}
}
save_stats(dev_name, curr, &sdev, iodev_nr, st_hdr_iodev);
}
/* Free the lines array */
for (l_c=0; l_c < line_nb; l_c++)
free(lines[l_c]);
/* Free structures corresponding to unregistered devices */
free_unregistered_entries(iodev_nr, st_hdr_iodev);
}
It would be great if this could be merged into the release so we all can enjoy
the sorted devices :)
Thanks!
Heiko
PS: Maybe someone cares to check my sorting algorithm, I have a history of
making off-by-ones and frankly, I don’t know if this is a good solution fort
sorting either.