Index: usr.bin/vmstat/drvstats.c =================================================================== RCS file: /cvsroot/src/usr.bin/vmstat/drvstats.c,v retrieving revision 1.10 diff -p -u -r1.10 drvstats.c --- usr.bin/vmstat/drvstats.c 5 Mar 2017 23:07:12 -0000 1.10 +++ usr.bin/vmstat/drvstats.c 2 Jul 2017 21:00:06 -0000 @@ -97,6 +97,31 @@ drvswap(void) if (!cur.select[i]) continue; + /* + * When a drive is replaced with one of the same + * name, the previous statistics are invalid. Try + * to detect this by validating counters and timestamp + */ + if ((cur.rxfer[i] == 0 && cur.wxfer[i] == 0) + || cur.rxfer[i] - last.rxfer[i] > INT64_MAX + || cur.wxfer[i] - last.wxfer[i] > INT64_MAX + || cur.seek[i] - last.seek[i] > INT64_MAX + || (cur.timestamp[i].tv_sec == 0 && + cur.timestamp[i].tv_usec == 0)) { + + last.rxfer[i] = cur.rxfer[i]; + last.wxfer[i] = cur.wxfer[i]; + last.seek[i] = cur.seek[i]; + last.rbytes[i] = cur.rbytes[i]; + last.wbytes[i] = cur.wbytes[i]; + + timerclear(&last.wait[i]); + timerclear(&last.time[i]); + timerclear(&last.waitsum[i]); + timerclear(&last.busysum[i]); + timerclear(&last.timestamp[i]); + } + /* Delta Values. */ SWAP(rxfer[i]); SWAP(wxfer[i]); @@ -108,6 +133,7 @@ drvswap(void) DELTA(time[i]); DELTA(waitsum[i]); DELTA(busysum[i]); + DELTA(timestamp[i]); } } @@ -151,7 +177,7 @@ cpuswap(void) void drvreadstats(void) { - size_t size, i; + size_t size, i, j, count; int mib[3]; mib[0] = CTL_HW; @@ -161,27 +187,46 @@ drvreadstats(void) size = ndrive * sizeof(struct io_sysctl); if (sysctl(mib, 3, drives, &size, NULL, 0) < 0) err(1, "sysctl hw.iostats failed"); + /* recalculate array length */ + count = size / sizeof(struct io_sysctl); -#define COPYF(x,k) cur.x[k] = drives[k].x -#define COPYT(x,k) do { \ - cur.x[k].tv_sec = drives[k].x##_sec; \ - cur.x[k].tv_usec = drives[k].x##_usec; \ +#define COPYF(x,k,l) cur.x[k] = drives[l].x +#define COPYT(x,k,l) do { \ + cur.x[k].tv_sec = drives[l].x##_sec; \ + cur.x[k].tv_usec = drives[l].x##_usec; \ } while (/* CONSTCOND */0) - for (i = 0; i < ndrive; i++) { + for (i = 0, j = 0; i < ndrive && j < count; i++) { - COPYF(rxfer, i); - COPYF(wxfer, i); - COPYF(seek, i); - COPYF(rbytes, i); - COPYF(wbytes, i); - - COPYT(wait, i); - COPYT(time, i); - COPYT(waitsum, i); - COPYT(busysum, i); + /* + * skip removed entries + * + * we cannot detect entries replaced with + * devices of the same name (e.g. unplug/replug). + */ + if (strcmp(cur.name[i], drives[j].name)) { + cur.select[i] = 0; + continue; + } + + COPYF(rxfer, i, j); + COPYF(wxfer, i, j); + COPYF(seek, i, j); + COPYF(rbytes, i, j); + COPYF(wbytes, i, j); + + COPYT(wait, i, j); + COPYT(time, i, j); + COPYT(waitsum, i, j); + COPYT(busysum, i, j); + COPYT(timestamp, i, j); + + ++j; } + /* shrink table to new size */ + ndrive = j; + mib[0] = CTL_KERN; mib[1] = KERN_TKSTAT; mib[2] = KERN_TKSTAT_NIN; @@ -295,6 +340,7 @@ drvinit(int selected) cur.wait = calloc(ndrive, sizeof(struct timeval)); cur.waitsum = calloc(ndrive, sizeof(struct timeval)); cur.busysum = calloc(ndrive, sizeof(struct timeval)); + cur.timestamp = calloc(ndrive, sizeof(struct timeval)); cur.rxfer = calloc(ndrive, sizeof(u_int64_t)); cur.wxfer = calloc(ndrive, sizeof(u_int64_t)); cur.seek = calloc(ndrive, sizeof(u_int64_t)); @@ -304,6 +350,7 @@ drvinit(int selected) last.wait = calloc(ndrive, sizeof(struct timeval)); last.waitsum = calloc(ndrive, sizeof(struct timeval)); last.busysum = calloc(ndrive, sizeof(struct timeval)); + last.timestamp = calloc(ndrive, sizeof(struct timeval)); last.rxfer = calloc(ndrive, sizeof(u_int64_t)); last.wxfer = calloc(ndrive, sizeof(u_int64_t)); last.seek = calloc(ndrive, sizeof(u_int64_t)); @@ -314,11 +361,13 @@ drvinit(int selected) if (cur.time == NULL || cur.wait == NULL || cur.waitsum == NULL || cur.busysum == NULL || + cur.timestamp == NULL || cur.rxfer == NULL || cur.wxfer == NULL || cur.seek == NULL || cur.rbytes == NULL || cur.wbytes == NULL || last.time == NULL || last.wait == NULL || last.waitsum == NULL || last.busysum == NULL || + last.timestamp == NULL || last.rxfer == NULL || last.wxfer == NULL || last.seek == NULL || last.rbytes == NULL || last.wbytes == NULL || @@ -335,8 +384,12 @@ drvinit(int selected) mib[2] = sizeof(struct io_sysctl); if (sysctl(mib, 3, drives, &size, NULL, 0) == -1) err(1, "sysctl hw.iostats failed"); + /* Recalculate array length */ + ndrive = size / sizeof(struct io_sysctl); for (i = 0; i < ndrive; i++) { - cur.name[i] = drives[i].name; + cur.name[i] = strndup(drives[i].name, sizeof(drives[i].name)); + if (cur.name[i] == NULL) + errx(1, "Memory allocation failure"); cur.select[i] = selected; } Index: usr.bin/vmstat/drvstats.h =================================================================== RCS file: /cvsroot/src/usr.bin/vmstat/drvstats.h,v retrieving revision 1.4 diff -p -u -r1.4 drvstats.h --- usr.bin/vmstat/drvstats.h 5 Mar 2017 23:07:12 -0000 1.4 +++ usr.bin/vmstat/drvstats.h 2 Jul 2017 21:00:06 -0000 @@ -39,7 +39,7 @@ /* poseur disk entry to hold the information we're interested in. */ struct _drive { int *select; /* Display stats for selected disks. */ - char **name; /* Disk names (sd0, wd1, etc). */ + char **name; /* Disk names (sd0, wd1, etc). */ u_int64_t *rxfer; /* # of read transfers. */ u_int64_t *wxfer; /* # of write transfers. */ u_int64_t *seek; /* # of seeks (currently unused). */ @@ -47,8 +47,9 @@ struct _drive { u_int64_t *wbytes; /* # of bytes written. */ struct timeval *time; /* Time spent in disk i/o. */ struct timeval *wait; /* Time spent in queue waiting. */ - struct timeval *busysum; /* Time busy * queue length */ - struct timeval *waitsum; /* Time waiting * queue length */ + struct timeval *busysum; /* Time busy * queue length */ + struct timeval *waitsum; /* Time waiting * queue length */ + struct timeval *timestamp; /* Disk sample time */ u_int64_t tk_nin; /* TTY Chars in. */ u_int64_t tk_nout; /* TTY Chars out. */ u_int64_t cp_time[CPUSTATES]; /* System timer ticks. */ Index: usr.bin/vmstat/vmstat.c =================================================================== RCS file: /cvsroot/src/usr.bin/vmstat/vmstat.c,v retrieving revision 1.216 diff -p -u -r1.216 vmstat.c --- usr.bin/vmstat/vmstat.c 5 Jan 2017 07:53:20 -0000 1.216 +++ usr.bin/vmstat/vmstat.c 2 Jul 2017 21:00:06 -0000 @@ -1113,20 +1113,23 @@ void drvstats(int *ovflwp) { size_t dn; - double etime; + double dtime; int ovflw = *ovflwp; /* Calculate disk stat deltas. */ cpuswap(); drvswap(); tkswap(); - etime = cur.cp_etime; for (dn = 0; dn < ndrive; ++dn) { + /* elapsed time for disk stats */ + dtime = (double)cur.timestamp[dn].tv_sec + + ((double)cur.timestamp[dn].tv_usec / (double)1000000); + if (!drv_select[dn]) continue; PRWORD(ovflw, " %*.0f", 3, 1, - (cur.rxfer[dn] + cur.wxfer[dn]) / etime); + (cur.rxfer[dn] + cur.wxfer[dn]) / dtime); } *ovflwp = ovflw; } Index: usr.sbin/iostat/iostat.c =================================================================== RCS file: /cvsroot/src/usr.sbin/iostat/iostat.c,v retrieving revision 1.64 diff -p -u -r1.64 iostat.c --- usr.sbin/iostat/iostat.c 5 Mar 2017 23:07:12 -0000 1.64 +++ usr.sbin/iostat/iostat.c 2 Jul 2017 21:00:06 -0000 @@ -112,6 +112,7 @@ static int wincols = 80; #define SHOW_STATS_ALL (SHOW_STATS_1 | SHOW_STATS_2 | SHOW_STATS_X | SHOW_STATS_Y) static void cpustats(void); +static double drive_time(double, int); static void drive_stats(double); static void drive_stats2(double); static void drive_statsx(double); @@ -321,15 +322,32 @@ header(void) printf("\n"); } +static double +drive_time(double etime, int dn) +{ + if (ISSET(todo, SHOW_TOTALS)) + return etime; + + if (cur.timestamp[dn].tv_sec || cur.timestamp[dn].tv_usec) { + etime = (double)cur.timestamp[dn].tv_sec + + ((double)cur.timestamp[dn].tv_usec / (double)1000000); + } + + return etime; +} + static void drive_stats(double etime) { size_t dn; - double atime, mbps; + double atime, dtime, mbps; for (dn = 0; dn < ndrive; ++dn) { if (!cur.select[dn]) continue; + + dtime = drive_time(etime, dn); + /* average Kbytes per transfer. */ if (cur.rxfer[dn] + cur.wxfer[dn]) mbps = ((cur.rbytes[dn] + cur.wbytes[dn]) / @@ -341,7 +359,7 @@ drive_stats(double etime) /* average transfers per second. */ (void)printf(" %4.0f", - (cur.rxfer[dn] + cur.wxfer[dn]) / etime); + (cur.rxfer[dn] + cur.wxfer[dn]) / dtime); /* time busy in drive activity */ atime = (double)cur.time[dn].tv_sec + @@ -353,7 +371,7 @@ drive_stats(double etime) (double)(1024 * 1024); else mbps = 0; - mbps /= etime; + mbps /= dtime; (void)printf(" %5.*f ", MAX(0, 3 - (int)floor(log10(fmax(1.0, mbps)))), mbps); } @@ -363,24 +381,26 @@ static void drive_stats2(double etime) { size_t dn; - double atime; + double atime, dtime; for (dn = 0; dn < ndrive; ++dn) { if (!cur.select[dn]) continue; + dtime = drive_time(etime, dn); + /* average kbytes per second. */ (void)printf(" %5.0f", - (cur.rbytes[dn] + cur.wbytes[dn]) / 1024.0 / etime); + (cur.rbytes[dn] + cur.wbytes[dn]) / 1024.0 / dtime); /* average transfers per second. */ (void)printf(" %5.0f", - (cur.rxfer[dn] + cur.wxfer[dn]) / etime); + (cur.rxfer[dn] + cur.wxfer[dn]) / dtime); /* average time busy in drive activity */ atime = (double)cur.time[dn].tv_sec + ((double)cur.time[dn].tv_usec / (double)1000000); - (void)printf(" %4.2f ", atime / etime); + (void)printf(" %4.2f ", atime / dtime); } } @@ -388,12 +408,14 @@ static void drive_statsx(double etime) { size_t dn; - double atime, kbps; + double atime, dtime, kbps; for (dn = 0; dn < ndrive; ++dn) { if (!cur.select[dn]) continue; + dtime = drive_time(etime, dn); + (void)printf("%-8.8s", cur.name[dn]); /* average read Kbytes per transfer */ @@ -405,17 +427,17 @@ drive_statsx(double etime) /* average read transfers (per second) */ - (void)printf(" %6.0f", cur.rxfer[dn] / etime); + (void)printf(" %6.0f", cur.rxfer[dn] / dtime); /* time read busy in drive activity */ atime = (double)cur.time[dn].tv_sec + ((double)cur.time[dn].tv_usec / (double)1000000); - (void)printf(" %6.2f", atime / etime); + (void)printf(" %6.2f", atime / dtime); /* average read megabytes (per second) */ (void)printf(" %8.2f", - cur.rbytes[dn] / (1024.0 * 1024) / etime); + cur.rbytes[dn] / (1024.0 * 1024) / dtime); /* average write Kbytes per transfer */ @@ -427,17 +449,17 @@ drive_statsx(double etime) /* average write transfers (per second) */ - (void)printf(" %6.0f", cur.wxfer[dn] / etime); + (void)printf(" %6.0f", cur.wxfer[dn] / dtime); /* time write busy in drive activity */ atime = (double)cur.time[dn].tv_sec + ((double)cur.time[dn].tv_usec / (double)1000000); - (void)printf(" %6.2f", atime / etime); + (void)printf(" %6.2f", atime / dtime); /* average write megabytes (per second) */ (void)printf(" %8.2f\n", - cur.wbytes[dn] / (1024.0 * 1024) / etime); + cur.wbytes[dn] / (1024.0 * 1024) / dtime); } } @@ -486,12 +508,14 @@ static void drive_statsy(double etime) { size_t dn; - double atime, await, abusysum, awaitsum; + double atime, await, abusysum, awaitsum, dtime; for (dn = 0; dn < ndrive; ++dn) { if (!cur.select[dn]) continue; + dtime = drive_time(etime, dn); + (void)printf("%-8.8s", cur.name[dn]); atime = (double)cur.time[dn].tv_sec + @@ -503,10 +527,10 @@ drive_statsy(double etime) awaitsum = (double)cur.waitsum[dn].tv_sec + ((double)cur.waitsum[dn].tv_usec / (double)1000000); - drive_statsy_io(etime, cur.rxfer[dn], cur.rbytes[dn]); + drive_statsy_io(dtime, cur.rxfer[dn], cur.rbytes[dn]); (void)printf(" "); - drive_statsy_io(etime, cur.wxfer[dn], cur.wbytes[dn]); - drive_statsy_q(etime, atime, await, abusysum, awaitsum, cur.rxfer[dn]+cur.wxfer[dn]); + drive_statsy_io(dtime, cur.wxfer[dn], cur.wbytes[dn]); + drive_statsy_q(dtime, atime, await, abusysum, awaitsum, cur.rxfer[dn]+cur.wxfer[dn]); (void)printf("\n"); }