summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authortmm <tmm@FreeBSD.org>2001-08-04 18:30:54 +0000
committertmm <tmm@FreeBSD.org>2001-08-04 18:30:54 +0000
commitfbdd58046b90150b1a878352cc6437ceffe60662 (patch)
treeb5bb6db65af69c9df354c866b46b26aef10539b1
parent37ac1a7962312051ecd4d5ac042973e6aab74d8b (diff)
downloadFreeBSD-src-fbdd58046b90150b1a878352cc6437ceffe60662.zip
FreeBSD-src-fbdd58046b90150b1a878352cc6437ceffe60662.tar.gz
Make use of the new features of libdevstat to allow iostat to work on
crash dumps, and make it use sysctl for all data retrievals in the "live" case (i.e. when not using iostat on a crash dump). Remove setgid kmem for the iostat executable, it is not needed any more after these changes. Reviewed by: ken
-rw-r--r--usr.sbin/iostat/Makefile2
-rw-r--r--usr.sbin/iostat/iostat.872
-rw-r--r--usr.sbin/iostat/iostat.c171
3 files changed, 151 insertions, 94 deletions
diff --git a/usr.sbin/iostat/Makefile b/usr.sbin/iostat/Makefile
index 5151442..c6903b6 100644
--- a/usr.sbin/iostat/Makefile
+++ b/usr.sbin/iostat/Makefile
@@ -5,8 +5,6 @@ MAINTAINER= ken@FreeBSD.ORG
PROG= iostat
MAN= iostat.8
-BINGRP= kmem
-BINMODE= 2555
DPADD= ${LIBKVM} ${LIBDEVSTAT}
LDADD= -lkvm -ldevstat
diff --git a/usr.sbin/iostat/iostat.8 b/usr.sbin/iostat/iostat.8
index f3e70ea..9d80a98 100644
--- a/usr.sbin/iostat/iostat.8
+++ b/usr.sbin/iostat/iostat.8
@@ -87,24 +87,30 @@ statistics
.Nm Iostat
displays kernel
.Tn I/O
-statistics on terminal, device and cpu
-operations.
+statistics on terminal, device and cpu operations.
+The first statistics that are printed are averaged over the system uptime.
+To get information about the current activity, a suitable wait time should
+be specified, so that the subsequent sets of printed statistics will be
+averaged over that time.
+.Pp
.Pp
The options are as follows:
.Bl -tag -width flag
.It Fl c
Repeat the display
.Ar count
-times. If no
+times.
+If no
.Ar wait
interval is specified, the default is 1 second.
.It Fl C
-Display CPU statistics. This is on by default, unless
+Display CPU statistics.
+This is on by default, unless
.Fl d
is specified.
.It Fl d
-Display only device statistics. If this flag is turned on, only device
-statistics will be displayed, unless
+Display only device statistics.
+If this flag is turned on, only device statistics will be displayed, unless
.Fl C
or
.Fl T
@@ -112,8 +118,9 @@ is also specfied to enable the display of CPU or TTY statistics.
.It Fl h
Put iostat in
.Sq top
-mode. In this mode, iostat will show devices in order from highest to
-lowest bytes per measurement cycle.
+mode.
+In this mode, iostat will show devices in order from highest to lowest bytes
+per measurement cycle.
.It Fl I
Display total statstics for a given time period, rather than average
statistics for each second during that time period.
@@ -138,14 +145,16 @@ Extract the name list from the specified system instead of the default
.It Fl o
Display old-style
.Nm
-device statistics. Sectors per second, transfers per second, and miliseconds
-per seek are displayed. If
+device statistics.
+Sectors per second, transfers per second, and miliseconds per seek are
+displayed.
+If
.Fl I
is specified, total blocks/sectors, total transfers, and
miliseconds per seek are displayed.
.It Fl t
-Specify which types of devices to display. There are three different
-categories of devices:
+Specify which types of devices to display.
+There are three different categories of devices:
.Pp
.Bl -tag -width indent -compact
.It device type:
@@ -196,23 +205,26 @@ Passthrough devices
.El
.Pp
The user must specify at least one device type, and may specify at most
-one device type from each category. Multiple device types in a single
-device type statement must be separated by commas.
+one device type from each category.
+Multiple device types in a single device type statement must be separated by
+commas.
.Pp
Any number of
.Fl t
-arguments may be specified on the command line. All
+arguments may be specified on the command line.
+All
.Fl t
arguments are ORed together to form a matching expression against which
-all devices in the system are compared. Any device that fully matches
-any
+all devices in the system are compared.
+Any device that fully matches any
.Fl t
argument will be included in the
.Nm
output, up to the number of devices that can be displayed in
80 columns, or the maximum number of devices specified by the user.
.It Fl T
-Display TTY statistics. This is on by default, unless
+Display TTY statistics.
+This is on by default, unless
.Fl d
is specified.
.It Fl w
@@ -237,10 +249,12 @@ characters read from terminals
characters written to terminals
.El
.It devices
-Device operations. The header of the field is the device name and unit number.
+Device operations.
+The header of the field is the device name and unit number.
.Nm
will display as many devices as will fit in a standard 80 column screen, or
-the maximum number of devices in the system, whichever is smaller. If
+the maximum number of devices in the system, whichever is smaller.
+If
.Fl n
is specified on the command line, iostat will display the smaller of the
requested number of devices, and the maximum number of devices in the system.
@@ -253,9 +267,9 @@ will not display more devices than will fit in an 80 column screen, unless
the
.Fl n
argument is given on the command line to specify a maximum number of
-devices to display. If fewer devices are specified on the command line
-than will fit in an 80 column screen, iostat will show only the specified
-devices.
+devices to display.
+If fewer devices are specified on the command line than will fit in an 80
+column screen, iostat will show only the specified devices.
.Pp
The standard
.Nm
@@ -372,7 +386,8 @@ Display total statistics every three seconds ad infinitum.
.Dl iostat -odICTw 2 -c 9
.Pp
Display total statistics using the old-style output format 9 times, with
-a two second interval between each measurement/display. The
+a two second interval between each measurement/display.
+The
.Fl d
flag generally disables the TTY and CPU displays, but since the
.Fl T
@@ -396,9 +411,10 @@ This version of
first appeared in
.Fx 3.0 .
.Sh BUGS
-You cannot display device statistics for a non-running system, due to the
-fact that the new device statistics interface is accessible only via
-.Xr sysctl 3 ,
-which does not provide a way to access non-running systems.
+The use of
+.Nm
+as a debugging tool for crash dumps is probably limited because there is
+currently no way to get statistics that only cover the time immediately before
+the crash.
.Sh AUTHORS
.An Kenneth Merry Aq ken@FreeBSD.org
diff --git a/usr.sbin/iostat/iostat.c b/usr.sbin/iostat/iostat.c
index 6568824..8a8cdc8 100644
--- a/usr.sbin/iostat/iostat.c
+++ b/usr.sbin/iostat/iostat.c
@@ -103,6 +103,7 @@
#include <sys/param.h>
#include <sys/errno.h>
#include <sys/dkstat.h>
+#include <sys/sysctl.h>
#include <err.h>
#include <ctype.h>
@@ -142,8 +143,9 @@ int dflag = 0, Iflag = 0, Cflag = 0, Tflag = 0, oflag = 0, Kflag = 0;
/* local function declarations */
static void usage(void);
static void phdr(int signo);
-static void devstats(int perf_select);
+static void devstats(int perf_select,double etime, int havelast);
static void cpustats(void);
+static void getsysctl(const char *, void *, size_t);
static void
usage(void)
@@ -170,7 +172,7 @@ main(int argc, char **argv)
struct devstat_match *matches;
int num_matches = 0;
char errbuf[_POSIX2_LINE_MAX];
- kvm_t *kd;
+ kvm_t *kd = NULL;
int hz, stathz;
int headercount;
long generation;
@@ -179,6 +181,8 @@ main(int argc, char **argv)
long select_generation;
char **specified_devices;
devstat_select_mode select_mode;
+ int use_kvm, havelast = 0;
+ struct clockinfo clkinfo;
matches = NULL;
maxshowdevs = 3;
@@ -224,8 +228,8 @@ main(int argc, char **argv)
break;
case 't':
tflag++;
- if (buildmatch(optarg, &matches,
- &num_matches) != 0)
+ if (devstat_buildmatch(optarg, &matches,
+ &num_matches) != 0)
errx(1, "%s", devstat_errbuf);
break;
case 'T':
@@ -247,19 +251,32 @@ main(int argc, char **argv)
argc -= optind;
argv += optind;
- /*
- * Discard setgid privileges if not the running kernel so that bad
- * guys can't print interesting stuff from kernel memory.
- */
- if (nlistf != NULL || memf != NULL)
- setgid(getgid());
+ if (nlistf == NULL && memf == NULL) {
+ use_kvm = 0;
+ getsysctl("kern.clockrate", &clkinfo, sizeof(clkinfo));
+ hz = clkinfo.hz;
+ } else {
+ use_kvm = 1;
+ kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf);
+
+ if (kd == 0)
+ errx(1, "kvm_openfiles: %s", errbuf);
+
+ if (kvm_nlist(kd, namelist) == -1)
+ errx(1, "kvm_nlist: %s", kvm_geterr(kd));
+
+ (void)nlread(X_HZ, hz);
+ (void)nlread(X_STATHZ, stathz);
+ if (stathz)
+ hz = stathz;
+ }
/*
* Make sure that the userland devstat version matches the kernel
* devstat version. If not, exit and print a message informing
* the user of his mistake.
*/
- if (checkversion() < 0)
+ if (devstat_checkversion(kd) < 0)
errx(1, "%s", devstat_errbuf);
/*
@@ -282,7 +299,7 @@ main(int argc, char **argv)
}
/* find out how many devices we have */
- if ((num_devices = getnumdevs()) < 0)
+ if ((num_devices = devstat_getnumdevs(kd)) < 0)
err(1, "can't get number of devices");
if ((cur.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo))) ==
@@ -299,7 +316,7 @@ main(int argc, char **argv)
* changed here, since it almost certainly has. We only look for
* errors.
*/
- if (getdevs(&cur) == -1)
+ if (devstat_getdevs(kd, &cur) == -1)
errx(1, "%s", devstat_errbuf);
num_devices = cur.dinfo->numdevs;
@@ -336,12 +353,12 @@ main(int argc, char **argv)
* device list has changed, so we don't look for return values of 0
* or 1. If we get back -1, though, there is an error.
*/
- if (selectdevs(&dev_select, &num_selected,
- &num_selections, &select_generation,
- generation, cur.dinfo->devices, num_devices,
- matches, num_matches,
- specified_devices, num_devices_specified,
- select_mode, maxshowdevs, hflag) == -1)
+ if (devstat_selectdevs(&dev_select, &num_selected,
+ &num_selections, &select_generation, generation,
+ cur.dinfo->devices, num_devices, matches,
+ num_matches, specified_devices,
+ num_devices_specified, select_mode, maxshowdevs,
+ hflag) == -1)
errx(1, "%s", devstat_errbuf);
/*
@@ -382,19 +399,6 @@ main(int argc, char **argv)
if ((wflag > 0) && (cflag == 0))
count = -1;
- kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf);
-
- if (kd == 0)
- errx(1, "kvm_openfiles: %s", errbuf);
-
- if (kvm_nlist(kd, namelist) == -1)
- errx(1, "kvm_nlist: %s", kvm_geterr(kd));
-
- (void)nlread(X_HZ, hz);
- (void)nlread(X_STATHZ, stathz);
- if (stathz)
- hz = stathz;
-
/*
* If the user stops the program (control-Z) and then resumes it,
* print out the header again.
@@ -410,12 +414,21 @@ main(int argc, char **argv)
phdr(0);
headercount = 20;
}
- (void)kvm_read(kd, namelist[X_TK_NIN].n_value,
- &cur.tk_nin, sizeof(cur.tk_nin));
- (void)kvm_read(kd, namelist[X_TK_NOUT].n_value,
- &cur.tk_nout, sizeof(cur.tk_nout));
- (void)kvm_read(kd, namelist[X_CP_TIME].n_value,
- cur.cp_time, sizeof(cur.cp_time));
+ if (use_kvm) {
+ (void)kvm_read(kd, namelist[X_TK_NIN].n_value,
+ &cur.tk_nin, sizeof(cur.tk_nin));
+ (void)kvm_read(kd, namelist[X_TK_NOUT].n_value,
+ &cur.tk_nout, sizeof(cur.tk_nout));
+ (void)kvm_read(kd, namelist[X_CP_TIME].n_value,
+ cur.cp_time, sizeof(cur.cp_time));
+ } else {
+ getsysctl("kern.tty_nin", &cur.tk_nin,
+ sizeof(cur.tk_nin));
+ getsysctl("kern.tty_nout", &cur.tk_nout,
+ sizeof(cur.tk_nout));
+ getsysctl("kern.cp_time", &cur.cp_time,
+ sizeof(cur.cp_time));
+ }
tmp_dinfo = last.dinfo;
last.dinfo = cur.dinfo;
@@ -425,12 +438,12 @@ main(int argc, char **argv)
/*
* Here what we want to do is refresh our device stats.
- * getdevs() returns 1 when the device list has changed.
+ * devstat_getdevs() returns 1 when the device list has changed.
* If the device list has changed, we want to go through
* the selection process again, in case a device that we
* were previously displaying has gone away.
*/
- switch (getdevs(&cur)) {
+ switch (devstat_getdevs(kd, &cur)) {
case -1:
errx(1, "%s", devstat_errbuf);
break;
@@ -439,13 +452,17 @@ main(int argc, char **argv)
num_devices = cur.dinfo->numdevs;
generation = cur.dinfo->generation;
- retval = selectdevs(&dev_select, &num_selected,
- &num_selections, &select_generation,
- generation, cur.dinfo->devices,
- num_devices, matches, num_matches,
- specified_devices,
- num_devices_specified,
- select_mode, maxshowdevs, hflag);
+ retval = devstat_selectdevs(&dev_select, &num_selected,
+ &num_selections,
+ &select_generation,
+ generation,
+ cur.dinfo->devices,
+ num_devices, matches,
+ num_matches,
+ specified_devices,
+ num_devices_specified,
+ select_mode, maxshowdevs,
+ hflag);
switch(retval) {
case -1:
errx(1, "%s", devstat_errbuf);
@@ -470,13 +487,17 @@ main(int argc, char **argv)
*/
if (hflag > 0) {
int retval;
- retval = selectdevs(&dev_select, &num_selected,
- &num_selections, &select_generation,
- generation, cur.dinfo->devices,
- num_devices, matches, num_matches,
- specified_devices,
- num_devices_specified,
- select_mode, maxshowdevs, hflag);
+ retval = devstat_selectdevs(&dev_select, &num_selected,
+ &num_selections,
+ &select_generation,
+ generation,
+ cur.dinfo->devices,
+ num_devices, matches,
+ num_matches,
+ specified_devices,
+ num_devices_specified,
+ select_mode, maxshowdevs,
+ hflag);
switch(retval) {
case -1:
errx(1,"%s", devstat_errbuf);
@@ -505,13 +526,13 @@ main(int argc, char **argv)
X(cp_time);
etime += cur.cp_time[i];
}
+ etime /= (float)hz;
if (etime == 0.0)
etime = 1.0;
- etime /= (float)hz;
if ((dflag == 0) || (Tflag > 0))
printf("%4.0f%5.0f", cur.tk_nin / etime,
cur.tk_nout/etime);
- devstats(hflag);
+ devstats(hflag, etime, havelast);
if ((dflag == 0) || (Cflag > 0))
cpustats();
printf("\n");
@@ -521,6 +542,7 @@ main(int argc, char **argv)
break;
sleep(waittime);
+ havelast = 1;
}
exit(0);
@@ -583,7 +605,7 @@ phdr(int signo)
}
static void
-devstats(int perf_select)
+devstats(int perf_select, double etime, int havelast)
{
register int dn;
long double transfers_per_second;
@@ -597,7 +619,11 @@ devstats(int perf_select)
* Calculate elapsed time up front, since it's the same for all
* devices.
*/
- busy_seconds = compute_etime(cur.busy_time, last.busy_time);
+ if (havelast)
+ busy_seconds = devstat_compute_etime(cur.busy_time,
+ last.busy_time);
+ else
+ busy_seconds = etime;
for (dn = 0; dn < num_devices; dn++) {
int di;
@@ -608,12 +634,17 @@ devstats(int perf_select)
di = dev_select[dn].position;
- if (compute_stats(&cur.dinfo->devices[di],
- &last.dinfo->devices[di], busy_seconds,
- &total_bytes, &total_transfers,
- &total_blocks, &kb_per_transfer,
- &transfers_per_second, &mb_per_second,
- &blocks_per_second, &ms_per_transaction)!= 0)
+ if (devstat_compute_statistics(&cur.dinfo->devices[di],
+ havelast ? &last.dinfo->devices[di] : NULL, busy_seconds,
+ DSM_TOTAL_BYTES, &total_bytes,
+ DSM_TOTAL_TRANSFERS, &total_transfers,
+ DSM_TOTAL_BLOCKS, &total_blocks,
+ DSM_KB_PER_TRANSFER, &kb_per_transfer,
+ DSM_TRANSFERS_PER_SECOND, &transfers_per_second,
+ DSM_MB_PER_SECOND, &mb_per_second,
+ DSM_BLOCKS_PER_SECOND, &blocks_per_second,
+ DSM_MS_PER_TRANSACTION, &ms_per_transaction,
+ DSM_NONE) != 0)
errx(1, "%s", devstat_errbuf);
if (perf_select != 0) {
@@ -677,3 +708,15 @@ cpustats(void)
printf("%3.0f",
100. * cur.cp_time[state] / (time ? time : 1));
}
+
+static void
+getsysctl(const char *name, void *ptr, size_t len)
+{
+ size_t nlen = len;
+
+ if (sysctlbyname(name, ptr, &nlen, NULL, 0) == -1)
+ err(1, "sysctl(%s...) failed", name);
+ if (nlen != len)
+ errx(1, "sysctl(%s...): expected %lu, got %lu", name,
+ (unsigned long)len, (unsigned long)nlen);
+}
OpenPOWER on IntegriCloud