Annotation of src/usr.bin/vmstat/dkstats.c, Revision 1.9
1.9 ! deraadt 1: /* $OpenBSD: dkstats.c,v 1.8 2000/10/03 03:12:16 aaron Exp $ */
1.2 deraadt 2: /* $NetBSD: dkstats.c,v 1.1 1996/05/10 23:19:27 thorpej Exp $ */
1.1 tholo 3:
4: /*
1.2 deraadt 5: * Copyright (c) 1996 John M. Vinopal
1.1 tholo 6: * All rights reserved.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
16: * 3. All advertising materials mentioning features or use of this software
17: * must display the following acknowledgement:
18: * This product includes software developed for the NetBSD Project
19: * by John M. Vinopal.
20: * 4. The name of the author may not be used to endorse or promote products
21: * derived from this software without specific prior written permission.
22: *
23: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28: * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
30: * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33: * SUCH DAMAGE.
34: */
35:
36: #include <sys/dkstat.h>
37: #include <sys/time.h>
38: #include <sys/disk.h>
39:
40: #include <err.h>
41: #include <fcntl.h>
42: #include <kvm.h>
43: #include <limits.h>
44: #include <nlist.h>
45: #include <stdio.h>
46: #include <stdlib.h>
47: #include <string.h>
48: #include <unistd.h>
49: #include "dkstats.h"
50:
51: static struct nlist namelist[] = {
52: #define X_TK_NIN 0
53: { "_tk_nin" }, /* tty characters in */
54: #define X_TK_NOUT 1
55: { "_tk_nout" }, /* tty characters out */
56: #define X_CP_TIME 2
57: { "_cp_time" }, /* system timer ticks */
58: #define X_HZ 3
59: { "_hz" }, /* ticks per second */
60: #define X_STATHZ 4
61: { "_stathz" },
62: #define X_DISK_COUNT 5
63: { "_disk_count" }, /* number of disks */
64: #define X_DISKLIST 6
65: { "_disklist" }, /* TAILQ of disks */
66: { NULL },
67: };
68:
69: /* Structures to hold the statistics. */
70: struct _disk cur, last;
71:
72: /* Kernel pointers: nlistf and memf defined in calling program. */
73: static kvm_t *kd = NULL;
74: extern char *nlistf;
75: extern char *memf;
76:
77: /* Pointer to list of disks. */
78: static struct disk *dk_drivehead = NULL;
79:
80: /* Backward compatibility references. */
81: int dk_ndrive = 0;
82: int *dk_select;
83: char **dr_name;
84:
85: #define KVM_ERROR(_string) { \
1.8 aaron 86: warnx("%s", (_string)); \
1.7 millert 87: errx(1, "%s", kvm_geterr(kd)); \
1.1 tholo 88: }
89:
90: /*
91: * Dereference the namelist pointer `v' and fill in the local copy
92: * 'p' which is of size 's'.
93: */
94: #define deref_nl(v, p, s) deref_kptr((void *)namelist[(v)].n_value, (p), (s));
95:
96: /* Missing from <sys/time.h> */
97: #define timerset(tvp, uvp) ((uvp)->tv_sec = (tvp)->tv_sec); \
98: ((uvp)->tv_usec = (tvp)->tv_usec)
99:
1.2 deraadt 100: static void deref_kptr __P((void *, void *, size_t));
1.1 tholo 101:
102: /*
103: * Take the delta between the present values and the last recorded
104: * values, storing the present values in the 'last' structure, and
105: * the delta values in the 'cur' structure.
106: */
107: void
108: dkswap()
109: {
110: #define SWAP(fld) tmp = cur.fld; \
111: cur.fld -= last.fld; \
112: last.fld = tmp
113: u_int64_t tmp;
114: int i;
115:
116: for (i = 0; i < dk_ndrive; i++) {
117: struct timeval tmp_timer;
118:
119: if (!cur.dk_select[i])
120: continue;
121:
122: /* Delta Values. */
123: SWAP(dk_xfer[i]);
124: SWAP(dk_seek[i]);
125: SWAP(dk_bytes[i]);
126:
127: /* Delta Time. */
128: timerclear(&tmp_timer);
129: timerset(&(cur.dk_time[i]), &tmp_timer);
130: timersub(&tmp_timer, &(last.dk_time[i]), &(cur.dk_time[i]));
131: timerclear(&(last.dk_time[i]));
132: timerset(&tmp_timer, &(last.dk_time[i]));
133: }
134: for (i = 0; i < CPUSTATES; i++) {
135: SWAP(cp_time[i]);
136: }
137: SWAP(tk_nin);
138: SWAP(tk_nout);
139:
140: #undef SWAP
141: }
142:
143: /*
144: * Read the disk statistics for each disk in the disk list.
145: * Also collect statistics for tty i/o and cpu ticks.
146: */
147: void
148: dkreadstats()
149: {
150: struct disk cur_disk, *p;
151: int i;
152:
153: p = dk_drivehead;
154:
155: for (i = 0; i < dk_ndrive; i++) {
156: deref_kptr(p, &cur_disk, sizeof(cur_disk));
157: cur.dk_xfer[i] = cur_disk.dk_xfer;
158: cur.dk_seek[i] = cur_disk.dk_seek;
159: cur.dk_bytes[i] = cur_disk.dk_bytes;
160: timerset(&(cur_disk.dk_time), &(cur.dk_time[i]));
161: p = cur_disk.dk_link.tqe_next;
162: }
163: deref_nl(X_CP_TIME, cur.cp_time, sizeof(cur.cp_time));
164: deref_nl(X_TK_NIN, &cur.tk_nin, sizeof(cur.tk_nin));
165: deref_nl(X_TK_NOUT, &cur.tk_nout, sizeof(cur.tk_nout));
166: }
167:
168: /*
169: * Perform all of the initialization and memory allocation needed to
170: * track disk statistics.
171: */
172: int
173: dkinit(select)
174: int select;
175: {
176: struct disklist_head disk_head;
177: struct disk cur_disk, *p;
178: char errbuf[_POSIX2_LINE_MAX];
179: static int once = 0;
180: extern int hz;
181: int i;
182:
183: if (once)
184: return(1);
185:
186: /* Open the kernel. */
187: if ((kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf)) == NULL)
188: errx(1, "kvm_openfiles: %s", errbuf);
189:
190: /* Obtain the namelist symbols from the kernel. */
191: if (kvm_nlist(kd, namelist))
192: KVM_ERROR("kvm_nlist failed to read symbols.");
193:
194: /* Get the number of attached drives. */
195: deref_nl(X_DISK_COUNT, &dk_ndrive, sizeof(dk_ndrive));
196:
197: if (dk_ndrive < 0)
198: errx(1, "invalid _disk_count %d.", dk_ndrive);
199: else {
200: /* Get a pointer to the first disk. */
201: deref_nl(X_DISKLIST, &disk_head, sizeof(disk_head));
202: dk_drivehead = disk_head.tqh_first;
203: }
204:
205: /* Get ticks per second. */
206: deref_nl(X_STATHZ, &hz, sizeof(hz));
207: if (!hz)
208: deref_nl(X_HZ, &hz, sizeof(hz));
209:
210: /* allocate space for the statistics */
211: cur.dk_time = calloc(dk_ndrive, sizeof(struct timeval));
212: cur.dk_xfer = calloc(dk_ndrive, sizeof(u_int64_t));
213: cur.dk_seek = calloc(dk_ndrive, sizeof(u_int64_t));
214: cur.dk_bytes = calloc(dk_ndrive, sizeof(u_int64_t));
215: last.dk_time = calloc(dk_ndrive, sizeof(struct timeval));
216: last.dk_xfer = calloc(dk_ndrive, sizeof(u_int64_t));
217: last.dk_seek = calloc(dk_ndrive, sizeof(u_int64_t));
218: last.dk_bytes = calloc(dk_ndrive, sizeof(u_int64_t));
219: cur.dk_select = calloc(dk_ndrive, sizeof(int));
220: cur.dk_name = calloc(dk_ndrive, sizeof(char *));
221:
1.9 ! deraadt 222: if (!cur.dk_time || !cur.dk_xfer || !cur.dk_seek || !cur.dk_bytes ||
! 223: !last.dk_time || !last.dk_xfer || !last.dk_seek ||
! 224: !last.dk_bytes || !cur.dk_select || !cur.dk_name)
1.1 tholo 225: errx(1, "Memory allocation failure.");
226:
227: /* Set up the compatibility interfaces. */
228: dk_select = cur.dk_select;
229: dr_name = cur.dk_name;
230:
231: /* Read the disk names and set intial selection. */
232: p = dk_drivehead;
233: for (i = 0; i < dk_ndrive; i++) {
234: char buf[10];
235: deref_kptr(p, &cur_disk, sizeof(cur_disk));
236: deref_kptr(cur_disk.dk_name, buf, sizeof(buf));
237: cur.dk_name[i] = strdup(buf);
1.9 ! deraadt 238: if (!cur.dk_name[i])
! 239: errx(1, "Memory allocation failure.");
1.1 tholo 240: cur.dk_select[i] = select;
241:
242: p = cur_disk.dk_link.tqe_next;
243: }
244:
245: /* Never do this initalization again. */
246: once = 1;
247: return(1);
248: }
249:
250: /*
251: * Dereference the kernel pointer `kptr' and fill in the local copy
252: * pointed to by `ptr'. The storage space must be pre-allocated,
253: * and the size of the copy passed in `len'.
254: */
255: static void
256: deref_kptr(kptr, ptr, len)
257: void *kptr, *ptr;
258: size_t len;
259: {
260: char buf[128];
261:
1.6 art 262: if (kvm_read(kd, (u_long)kptr, ptr, len) != len) {
1.1 tholo 263: bzero(buf, sizeof(buf));
264: snprintf(buf, (sizeof(buf) - 1),
1.2 deraadt 265: "can't dereference kptr 0x%lx", (u_long)kptr);
1.1 tholo 266: KVM_ERROR(buf);
267: }
268: }