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");
 	}
