1 |
|
|
/* $OpenBSD: dkstats.c,v 1.38 2015/12/24 03:25:08 mmcc Exp $ */ |
2 |
|
|
/* $NetBSD: dkstats.c,v 1.1 1996/05/10 23:19:27 thorpej Exp $ */ |
3 |
|
|
|
4 |
|
|
/* |
5 |
|
|
* Copyright (c) 1996 John M. Vinopal |
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/time.h> |
37 |
|
|
#include <sys/disk.h> |
38 |
|
|
#include <sys/sched.h> |
39 |
|
|
#include <sys/sysctl.h> |
40 |
|
|
#include <sys/tty.h> |
41 |
|
|
|
42 |
|
|
#include <err.h> |
43 |
|
|
#include <fcntl.h> |
44 |
|
|
#include <kvm.h> |
45 |
|
|
#include <limits.h> |
46 |
|
|
#include <nlist.h> |
47 |
|
|
#include <stdio.h> |
48 |
|
|
#include <stdlib.h> |
49 |
|
|
#include <string.h> |
50 |
|
|
#include <unistd.h> |
51 |
|
|
#include "dkstats.h" |
52 |
|
|
|
53 |
|
|
#if !defined(NOKVM) |
54 |
|
|
static struct nlist namelist[] = { |
55 |
|
|
#define X_TK_NIN 0 /* sysctl */ |
56 |
|
|
{ "_tk_nin" }, |
57 |
|
|
#define X_TK_NOUT 1 /* sysctl */ |
58 |
|
|
{ "_tk_nout" }, |
59 |
|
|
#define X_CP_TIME 2 /* sysctl */ |
60 |
|
|
{ "_cp_time" }, |
61 |
|
|
#define X_HZ 3 /* sysctl */ |
62 |
|
|
{ "_hz" }, |
63 |
|
|
#define X_STATHZ 4 /* sysctl */ |
64 |
|
|
{ "_stathz" }, |
65 |
|
|
#define X_DISK_COUNT 5 /* sysctl */ |
66 |
|
|
{ "_disk_count" }, |
67 |
|
|
#define X_DISKLIST 6 /* sysctl */ |
68 |
|
|
{ "_disklist" }, |
69 |
|
|
{ NULL }, |
70 |
|
|
}; |
71 |
|
|
#define KVM_ERROR(_string) { \ |
72 |
|
|
warnx("%s", (_string)); \ |
73 |
|
|
errx(1, "%s", kvm_geterr(kd)); \ |
74 |
|
|
} |
75 |
|
|
|
76 |
|
|
/* |
77 |
|
|
* Dereference the namelist pointer `v' and fill in the local copy |
78 |
|
|
* 'p' which is of size 's'. |
79 |
|
|
*/ |
80 |
|
|
#define deref_nl(v, p, s) deref_kptr((void *)namelist[(v)].n_value, (p), (s)); |
81 |
|
|
static void deref_kptr(void *, void *, size_t); |
82 |
|
|
#endif /* !defined(NOKVM) */ |
83 |
|
|
|
84 |
|
|
/* Structures to hold the statistics. */ |
85 |
|
|
struct _disk cur, last; |
86 |
|
|
|
87 |
|
|
/* Kernel pointers: nlistf and memf defined in calling program. */ |
88 |
|
|
#if !defined(NOKVM) |
89 |
|
|
extern kvm_t *kd; |
90 |
|
|
#endif |
91 |
|
|
extern char *nlistf; |
92 |
|
|
extern char *memf; |
93 |
|
|
|
94 |
|
|
#if !defined(NOKVM) |
95 |
|
|
/* Pointer to list of disks. */ |
96 |
|
|
static struct disk *dk_drivehead = NULL; |
97 |
|
|
#endif |
98 |
|
|
|
99 |
|
|
/* Backward compatibility references. */ |
100 |
|
|
int dk_ndrive = 0; |
101 |
|
|
int *dk_select; |
102 |
|
|
char **dr_name; |
103 |
|
|
|
104 |
|
|
/* Missing from <sys/time.h> */ |
105 |
|
|
#define timerset(tvp, uvp) \ |
106 |
|
|
((uvp)->tv_sec = (tvp)->tv_sec); \ |
107 |
|
|
((uvp)->tv_usec = (tvp)->tv_usec) |
108 |
|
|
|
109 |
|
|
#define SWAP(fld) tmp = cur.fld; \ |
110 |
|
|
cur.fld -= last.fld; \ |
111 |
|
|
last.fld = tmp |
112 |
|
|
|
113 |
|
|
/* |
114 |
|
|
* Take the delta between the present values and the last recorded |
115 |
|
|
* values, storing the present values in the 'last' structure, and |
116 |
|
|
* the delta values in the 'cur' structure. |
117 |
|
|
*/ |
118 |
|
|
void |
119 |
|
|
dkswap(void) |
120 |
|
|
{ |
121 |
|
|
u_int64_t tmp; |
122 |
|
|
int i; |
123 |
|
|
|
124 |
|
|
for (i = 0; i < cur.dk_ndrive; i++) { |
125 |
|
|
struct timeval tmp_timer; |
126 |
|
|
|
127 |
|
|
if (!cur.dk_select[i]) |
128 |
|
|
continue; |
129 |
|
|
|
130 |
|
|
/* Delta Values. */ |
131 |
|
|
SWAP(dk_rxfer[i]); |
132 |
|
|
SWAP(dk_wxfer[i]); |
133 |
|
|
SWAP(dk_seek[i]); |
134 |
|
|
SWAP(dk_rbytes[i]); |
135 |
|
|
SWAP(dk_wbytes[i]); |
136 |
|
|
|
137 |
|
|
/* Delta Time. */ |
138 |
|
|
timerclear(&tmp_timer); |
139 |
|
|
timerset(&(cur.dk_time[i]), &tmp_timer); |
140 |
|
|
timersub(&tmp_timer, &(last.dk_time[i]), &(cur.dk_time[i])); |
141 |
|
|
timerclear(&(last.dk_time[i])); |
142 |
|
|
timerset(&tmp_timer, &(last.dk_time[i])); |
143 |
|
|
} |
144 |
|
|
for (i = 0; i < CPUSTATES; i++) { |
145 |
|
|
long ltmp; |
146 |
|
|
|
147 |
|
|
ltmp = cur.cp_time[i]; |
148 |
|
|
cur.cp_time[i] -= last.cp_time[i]; |
149 |
|
|
last.cp_time[i] = ltmp; |
150 |
|
|
} |
151 |
|
|
SWAP(tk_nin); |
152 |
|
|
SWAP(tk_nout); |
153 |
|
|
|
154 |
|
|
#undef SWAP |
155 |
|
|
} |
156 |
|
|
|
157 |
|
|
/* |
158 |
|
|
* Read the disk statistics for each disk in the disk list. |
159 |
|
|
* Also collect statistics for tty i/o and cpu ticks. |
160 |
|
|
*/ |
161 |
|
|
void |
162 |
|
|
dkreadstats(void) |
163 |
|
|
{ |
164 |
|
|
#if !defined(NOKVM) |
165 |
|
|
struct disk cur_disk, *p; |
166 |
|
|
#endif |
167 |
|
|
int i, j, mib[3]; |
168 |
|
|
size_t size; |
169 |
|
|
char *disknames, *name, *bufpp, **dk_name; |
170 |
|
|
struct diskstats *q; |
171 |
|
|
|
172 |
|
|
last.dk_ndrive = cur.dk_ndrive; |
173 |
|
|
|
174 |
|
|
if (nlistf == NULL && memf == NULL) { |
175 |
|
|
/* Get the number of attached drives. */ |
176 |
|
|
mib[0] = CTL_HW; |
177 |
|
|
mib[1] = HW_DISKCOUNT; |
178 |
|
|
size = sizeof(dk_ndrive); |
179 |
|
|
if (sysctl(mib, 2, &dk_ndrive, &size, NULL, 0) < 0 ) { |
180 |
|
|
warn("could not read hw.diskcount"); |
181 |
|
|
dk_ndrive = 0; |
182 |
|
|
} |
183 |
|
|
|
184 |
|
|
if (cur.dk_ndrive != dk_ndrive) { |
185 |
|
|
/* Re-read the disk names. */ |
186 |
|
|
dk_name = calloc((size_t)dk_ndrive, sizeof(char *)); |
187 |
|
|
if (dk_name == NULL) |
188 |
|
|
err(1, NULL); |
189 |
|
|
mib[0] = CTL_HW; |
190 |
|
|
mib[1] = HW_DISKNAMES; |
191 |
|
|
size = 0; |
192 |
|
|
if (sysctl(mib, 2, NULL, &size, NULL, 0) < 0) |
193 |
|
|
err(1, "can't get hw.disknames"); |
194 |
|
|
disknames = malloc(size); |
195 |
|
|
if (disknames == NULL) |
196 |
|
|
err(1, NULL); |
197 |
|
|
if (sysctl(mib, 2, disknames, &size, NULL, 0) < 0) |
198 |
|
|
err(1, "can't get hw.disknames"); |
199 |
|
|
bufpp = disknames; |
200 |
|
|
for (i = 0; i < dk_ndrive && |
201 |
|
|
(name = strsep(&bufpp, ",")) != NULL; i++) |
202 |
|
|
dk_name[i] = name; |
203 |
|
|
for (i = 0; i < dk_ndrive; i++) { |
204 |
|
|
char *p = strchr(dk_name[i], ':'); |
205 |
|
|
if (p) |
206 |
|
|
*p = '\0'; |
207 |
|
|
} |
208 |
|
|
disknames = cur.dk_name[0]; /* To free old names. */ |
209 |
|
|
|
210 |
|
|
if (dk_ndrive < cur.dk_ndrive) { |
211 |
|
|
for (i = 0, j = 0; i < dk_ndrive; i++, j++) { |
212 |
|
|
while (j < cur.dk_ndrive && |
213 |
|
|
strcmp(cur.dk_name[j], dk_name[i])) |
214 |
|
|
j++; |
215 |
|
|
if (i == j) continue; |
216 |
|
|
|
217 |
|
|
if (j >= cur.dk_ndrive) { |
218 |
|
|
cur.dk_select[i] = 1; |
219 |
|
|
last.dk_rxfer[i] = 0; |
220 |
|
|
last.dk_wxfer[i] = 0; |
221 |
|
|
last.dk_seek[i] = 0; |
222 |
|
|
last.dk_rbytes[i] = 0; |
223 |
|
|
last.dk_wbytes[i] = 0; |
224 |
|
|
memset(&last.dk_time[i], 0, |
225 |
|
|
sizeof(struct timeval)); |
226 |
|
|
continue; |
227 |
|
|
} |
228 |
|
|
|
229 |
|
|
cur.dk_select[i] = cur.dk_select[j]; |
230 |
|
|
last.dk_rxfer[i] = last.dk_rxfer[j]; |
231 |
|
|
last.dk_wxfer[i] = last.dk_wxfer[j]; |
232 |
|
|
last.dk_seek[i] = last.dk_seek[j]; |
233 |
|
|
last.dk_rbytes[i] = last.dk_rbytes[j]; |
234 |
|
|
last.dk_wbytes[i] = last.dk_wbytes[j]; |
235 |
|
|
last.dk_time[i] = last.dk_time[j]; |
236 |
|
|
} |
237 |
|
|
|
238 |
|
|
cur.dk_select = realloc(cur.dk_select, |
239 |
|
|
dk_ndrive * sizeof(*cur.dk_select)); |
240 |
|
|
cur.dk_rxfer = realloc(cur.dk_rxfer, |
241 |
|
|
dk_ndrive * sizeof(*cur.dk_rxfer)); |
242 |
|
|
cur.dk_wxfer = realloc(cur.dk_wxfer, |
243 |
|
|
dk_ndrive * sizeof(*cur.dk_wxfer)); |
244 |
|
|
cur.dk_seek = realloc(cur.dk_seek, |
245 |
|
|
dk_ndrive * sizeof(*cur.dk_seek)); |
246 |
|
|
cur.dk_rbytes = realloc(cur.dk_rbytes, |
247 |
|
|
dk_ndrive * sizeof(*cur.dk_rbytes)); |
248 |
|
|
cur.dk_wbytes = realloc(cur.dk_wbytes, |
249 |
|
|
dk_ndrive * sizeof(*cur.dk_wbytes)); |
250 |
|
|
cur.dk_time = realloc(cur.dk_time, |
251 |
|
|
dk_ndrive * sizeof(*cur.dk_time)); |
252 |
|
|
last.dk_rxfer = realloc(last.dk_rxfer, |
253 |
|
|
dk_ndrive * sizeof(*last.dk_rxfer)); |
254 |
|
|
last.dk_wxfer = realloc(last.dk_wxfer, |
255 |
|
|
dk_ndrive * sizeof(*last.dk_wxfer)); |
256 |
|
|
last.dk_seek = realloc(last.dk_seek, |
257 |
|
|
dk_ndrive * sizeof(*last.dk_seek)); |
258 |
|
|
last.dk_rbytes = realloc(last.dk_rbytes, |
259 |
|
|
dk_ndrive * sizeof(*last.dk_rbytes)); |
260 |
|
|
last.dk_wbytes = realloc(last.dk_wbytes, |
261 |
|
|
dk_ndrive * sizeof(*last.dk_wbytes)); |
262 |
|
|
last.dk_time = realloc(last.dk_time, |
263 |
|
|
dk_ndrive * sizeof(*last.dk_time)); |
264 |
|
|
|
265 |
|
|
if (!cur.dk_select || !cur.dk_rxfer || |
266 |
|
|
!cur.dk_wxfer || !cur.dk_seek || |
267 |
|
|
!cur.dk_rbytes || !cur.dk_wbytes || |
268 |
|
|
!cur.dk_time || !last.dk_rxfer || |
269 |
|
|
!last.dk_wxfer || !last.dk_seek || |
270 |
|
|
!last.dk_rbytes || !last.dk_wbytes || |
271 |
|
|
!last.dk_time) |
272 |
|
|
errx(1, "Memory allocation failure."); |
273 |
|
|
} else { |
274 |
|
|
cur.dk_select = realloc(cur.dk_select, |
275 |
|
|
dk_ndrive * sizeof(*cur.dk_select)); |
276 |
|
|
cur.dk_rxfer = realloc(cur.dk_rxfer, |
277 |
|
|
dk_ndrive * sizeof(*cur.dk_rxfer)); |
278 |
|
|
cur.dk_wxfer = realloc(cur.dk_wxfer, |
279 |
|
|
dk_ndrive * sizeof(*cur.dk_wxfer)); |
280 |
|
|
cur.dk_seek = realloc(cur.dk_seek, |
281 |
|
|
dk_ndrive * sizeof(*cur.dk_seek)); |
282 |
|
|
cur.dk_rbytes = realloc(cur.dk_rbytes, |
283 |
|
|
dk_ndrive * sizeof(*cur.dk_rbytes)); |
284 |
|
|
cur.dk_wbytes = realloc(cur.dk_wbytes, |
285 |
|
|
dk_ndrive * sizeof(*cur.dk_wbytes)); |
286 |
|
|
cur.dk_time = realloc(cur.dk_time, |
287 |
|
|
dk_ndrive * sizeof(*cur.dk_time)); |
288 |
|
|
last.dk_rxfer = realloc(last.dk_rxfer, |
289 |
|
|
dk_ndrive * sizeof(*last.dk_rxfer)); |
290 |
|
|
last.dk_wxfer = realloc(last.dk_wxfer, |
291 |
|
|
dk_ndrive * sizeof(*last.dk_wxfer)); |
292 |
|
|
last.dk_seek = realloc(last.dk_seek, |
293 |
|
|
dk_ndrive * sizeof(*last.dk_seek)); |
294 |
|
|
last.dk_rbytes = realloc(last.dk_rbytes, |
295 |
|
|
dk_ndrive * sizeof(*last.dk_rbytes)); |
296 |
|
|
last.dk_wbytes = realloc(last.dk_wbytes, |
297 |
|
|
dk_ndrive * sizeof(*last.dk_wbytes)); |
298 |
|
|
last.dk_time = realloc(last.dk_time, |
299 |
|
|
dk_ndrive * sizeof(*last.dk_time)); |
300 |
|
|
|
301 |
|
|
if (!cur.dk_select || !cur.dk_rxfer || |
302 |
|
|
!cur.dk_wxfer || !cur.dk_seek || |
303 |
|
|
!cur.dk_rbytes || !cur.dk_wbytes || |
304 |
|
|
!cur.dk_time || !last.dk_rxfer || |
305 |
|
|
!last.dk_wxfer || !last.dk_seek || |
306 |
|
|
!last.dk_rbytes || !last.dk_wbytes || |
307 |
|
|
!last.dk_time) |
308 |
|
|
errx(1, "Memory allocation failure."); |
309 |
|
|
|
310 |
|
|
for (i = dk_ndrive - 1, j = cur.dk_ndrive - 1; |
311 |
|
|
i >= 0; i--) { |
312 |
|
|
|
313 |
|
|
if (j < 0 || |
314 |
|
|
strcmp(cur.dk_name[j], dk_name[i])) |
315 |
|
|
{ |
316 |
|
|
cur.dk_select[i] = 1; |
317 |
|
|
last.dk_rxfer[i] = 0; |
318 |
|
|
last.dk_wxfer[i] = 0; |
319 |
|
|
last.dk_seek[i] = 0; |
320 |
|
|
last.dk_rbytes[i] = 0; |
321 |
|
|
last.dk_wbytes[i] = 0; |
322 |
|
|
memset(&last.dk_time[i], 0, |
323 |
|
|
sizeof(struct timeval)); |
324 |
|
|
continue; |
325 |
|
|
} |
326 |
|
|
|
327 |
|
|
if (i > j) { |
328 |
|
|
cur.dk_select[i] = |
329 |
|
|
cur.dk_select[j]; |
330 |
|
|
last.dk_rxfer[i] = |
331 |
|
|
last.dk_rxfer[j]; |
332 |
|
|
last.dk_wxfer[i] = |
333 |
|
|
last.dk_wxfer[j]; |
334 |
|
|
last.dk_seek[i] = |
335 |
|
|
last.dk_seek[j]; |
336 |
|
|
last.dk_rbytes[i] = |
337 |
|
|
last.dk_rbytes[j]; |
338 |
|
|
last.dk_wbytes[i] = |
339 |
|
|
last.dk_wbytes[j]; |
340 |
|
|
last.dk_time[i] = |
341 |
|
|
last.dk_time[j]; |
342 |
|
|
} |
343 |
|
|
j--; |
344 |
|
|
} |
345 |
|
|
} |
346 |
|
|
|
347 |
|
|
cur.dk_ndrive = dk_ndrive; |
348 |
|
|
free(disknames); |
349 |
|
|
cur.dk_name = dk_name; |
350 |
|
|
dr_name = cur.dk_name; |
351 |
|
|
dk_select = cur.dk_select; |
352 |
|
|
} |
353 |
|
|
|
354 |
|
|
size = cur.dk_ndrive * sizeof(struct diskstats); |
355 |
|
|
mib[0] = CTL_HW; |
356 |
|
|
mib[1] = HW_DISKSTATS; |
357 |
|
|
q = malloc(size); |
358 |
|
|
if (q == NULL) |
359 |
|
|
err(1, NULL); |
360 |
|
|
if (sysctl(mib, 2, q, &size, NULL, 0) < 0) { |
361 |
|
|
#ifdef DEBUG |
362 |
|
|
warn("could not read hw.diskstats"); |
363 |
|
|
#endif /* DEBUG */ |
364 |
|
|
memset(q, 0, cur.dk_ndrive * sizeof(struct diskstats)); |
365 |
|
|
} |
366 |
|
|
|
367 |
|
|
for (i = 0; i < cur.dk_ndrive; i++) { |
368 |
|
|
cur.dk_rxfer[i] = q[i].ds_rxfer; |
369 |
|
|
cur.dk_wxfer[i] = q[i].ds_wxfer; |
370 |
|
|
cur.dk_seek[i] = q[i].ds_seek; |
371 |
|
|
cur.dk_rbytes[i] = q[i].ds_rbytes; |
372 |
|
|
cur.dk_wbytes[i] = q[i].ds_wbytes; |
373 |
|
|
timerset(&(q[i].ds_time), &(cur.dk_time[i])); |
374 |
|
|
} |
375 |
|
|
free(q); |
376 |
|
|
|
377 |
|
|
size = sizeof(cur.cp_time); |
378 |
|
|
mib[0] = CTL_KERN; |
379 |
|
|
mib[1] = KERN_CPTIME; |
380 |
|
|
if (sysctl(mib, 2, cur.cp_time, &size, NULL, 0) < 0) { |
381 |
|
|
warn("could not read kern.cp_time"); |
382 |
|
|
memset(cur.cp_time, 0, sizeof(cur.cp_time)); |
383 |
|
|
} |
384 |
|
|
size = sizeof(cur.tk_nin); |
385 |
|
|
mib[0] = CTL_KERN; |
386 |
|
|
mib[1] = KERN_TTY; |
387 |
|
|
mib[2] = KERN_TTY_TKNIN; |
388 |
|
|
if (sysctl(mib, 3, &cur.tk_nin, &size, NULL, 0) < 0) { |
389 |
|
|
warn("could not read kern.tty.tk_nin"); |
390 |
|
|
cur.tk_nin = 0; |
391 |
|
|
} |
392 |
|
|
size = sizeof(cur.tk_nin); |
393 |
|
|
mib[0] = CTL_KERN; |
394 |
|
|
mib[1] = KERN_TTY; |
395 |
|
|
mib[2] = KERN_TTY_TKNOUT; |
396 |
|
|
if (sysctl(mib, 3, &cur.tk_nout, &size, NULL, 0) < 0) { |
397 |
|
|
warn("could not read kern.tty.tk_nout"); |
398 |
|
|
cur.tk_nout = 0; |
399 |
|
|
} |
400 |
|
|
} else { |
401 |
|
|
#if !defined(NOKVM) |
402 |
|
|
p = dk_drivehead; |
403 |
|
|
|
404 |
|
|
for (i = 0; i < cur.dk_ndrive; i++) { |
405 |
|
|
deref_kptr(p, &cur_disk, sizeof(cur_disk)); |
406 |
|
|
cur.dk_rxfer[i] = cur_disk.dk_rxfer; |
407 |
|
|
cur.dk_wxfer[i] = cur_disk.dk_wxfer; |
408 |
|
|
cur.dk_seek[i] = cur_disk.dk_seek; |
409 |
|
|
cur.dk_rbytes[i] = cur_disk.dk_rbytes; |
410 |
|
|
cur.dk_wbytes[i] = cur_disk.dk_wbytes; |
411 |
|
|
timerset(&(cur_disk.dk_time), &(cur.dk_time[i])); |
412 |
|
|
p = TAILQ_NEXT(&cur_disk, dk_link); |
413 |
|
|
} |
414 |
|
|
deref_nl(X_CP_TIME, cur.cp_time, sizeof(cur.cp_time)); |
415 |
|
|
deref_nl(X_TK_NIN, &cur.tk_nin, sizeof(cur.tk_nin)); |
416 |
|
|
deref_nl(X_TK_NOUT, &cur.tk_nout, sizeof(cur.tk_nout)); |
417 |
|
|
#endif /* !defined(NOKVM) */ |
418 |
|
|
} |
419 |
|
|
} |
420 |
|
|
|
421 |
|
|
/* |
422 |
|
|
* Perform all of the initialization and memory allocation needed to |
423 |
|
|
* track disk statistics. |
424 |
|
|
*/ |
425 |
|
|
int |
426 |
|
|
dkinit(int sel) |
427 |
|
|
{ |
428 |
|
|
#if !defined(NOKVM) |
429 |
|
|
struct disklist_head disk_head; |
430 |
|
|
struct disk cur_disk, *p; |
431 |
|
|
char errbuf[_POSIX2_LINE_MAX]; |
432 |
|
|
#endif |
433 |
|
|
static int once = 0; |
434 |
|
|
extern int hz; |
435 |
|
|
int i, mib[2]; |
436 |
|
|
size_t size; |
437 |
|
|
struct clockinfo clkinfo; |
438 |
|
|
char *disknames, *name, *bufpp; |
439 |
|
|
|
440 |
|
|
if (once) |
441 |
|
|
return(1); |
442 |
|
|
|
443 |
|
|
if (nlistf != NULL || memf != NULL) { |
444 |
|
|
#if !defined(NOKVM) |
445 |
|
|
/* Open the kernel. */ |
446 |
|
|
if (kd == NULL && |
447 |
|
|
(kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, |
448 |
|
|
errbuf)) == NULL) |
449 |
|
|
errx(1, "kvm_openfiles: %s", errbuf); |
450 |
|
|
|
451 |
|
|
/* Obtain the namelist symbols from the kernel. */ |
452 |
|
|
if (kvm_nlist(kd, namelist)) |
453 |
|
|
KVM_ERROR("kvm_nlist failed to read symbols."); |
454 |
|
|
|
455 |
|
|
/* Get the number of attached drives. */ |
456 |
|
|
deref_nl(X_DISK_COUNT, &cur.dk_ndrive, sizeof(cur.dk_ndrive)); |
457 |
|
|
|
458 |
|
|
if (cur.dk_ndrive < 0) |
459 |
|
|
errx(1, "invalid _disk_count %d.", cur.dk_ndrive); |
460 |
|
|
|
461 |
|
|
/* Get a pointer to the first disk. */ |
462 |
|
|
deref_nl(X_DISKLIST, &disk_head, sizeof(disk_head)); |
463 |
|
|
dk_drivehead = TAILQ_FIRST(&disk_head); |
464 |
|
|
|
465 |
|
|
/* Get ticks per second. */ |
466 |
|
|
deref_nl(X_STATHZ, &hz, sizeof(hz)); |
467 |
|
|
if (!hz) |
468 |
|
|
deref_nl(X_HZ, &hz, sizeof(hz)); |
469 |
|
|
#endif /* !defined(NOKVM) */ |
470 |
|
|
} else { |
471 |
|
|
/* Get the number of attached drives. */ |
472 |
|
|
mib[0] = CTL_HW; |
473 |
|
|
mib[1] = HW_DISKCOUNT; |
474 |
|
|
size = sizeof(cur.dk_ndrive); |
475 |
|
|
if (sysctl(mib, 2, &cur.dk_ndrive, &size, NULL, 0) < 0 ) { |
476 |
|
|
warn("could not read hw.diskcount"); |
477 |
|
|
cur.dk_ndrive = 0; |
478 |
|
|
} |
479 |
|
|
|
480 |
|
|
/* Get ticks per second. */ |
481 |
|
|
mib[0] = CTL_KERN; |
482 |
|
|
mib[1] = KERN_CLOCKRATE; |
483 |
|
|
size = sizeof(clkinfo); |
484 |
|
|
if (sysctl(mib, 2, &clkinfo, &size, NULL, 0) < 0) { |
485 |
|
|
warn("could not read kern.clockrate"); |
486 |
|
|
hz = 0; |
487 |
|
|
} else |
488 |
|
|
hz = clkinfo.stathz; |
489 |
|
|
} |
490 |
|
|
|
491 |
|
|
/* allocate space for the statistics */ |
492 |
|
|
cur.dk_time = calloc((size_t)cur.dk_ndrive, sizeof(struct timeval)); |
493 |
|
|
cur.dk_rxfer = calloc((size_t)cur.dk_ndrive, sizeof(u_int64_t)); |
494 |
|
|
cur.dk_wxfer = calloc((size_t)cur.dk_ndrive, sizeof(u_int64_t)); |
495 |
|
|
cur.dk_seek = calloc((size_t)cur.dk_ndrive, sizeof(u_int64_t)); |
496 |
|
|
cur.dk_rbytes = calloc((size_t)cur.dk_ndrive, sizeof(u_int64_t)); |
497 |
|
|
cur.dk_wbytes = calloc((size_t)cur.dk_ndrive, sizeof(u_int64_t)); |
498 |
|
|
cur.dk_select = calloc((size_t)cur.dk_ndrive, sizeof(int)); |
499 |
|
|
cur.dk_name = calloc((size_t)cur.dk_ndrive, sizeof(char *)); |
500 |
|
|
last.dk_time = calloc((size_t)cur.dk_ndrive, sizeof(struct timeval)); |
501 |
|
|
last.dk_rxfer = calloc((size_t)cur.dk_ndrive, sizeof(u_int64_t)); |
502 |
|
|
last.dk_wxfer = calloc((size_t)cur.dk_ndrive, sizeof(u_int64_t)); |
503 |
|
|
last.dk_seek = calloc((size_t)cur.dk_ndrive, sizeof(u_int64_t)); |
504 |
|
|
last.dk_rbytes = calloc((size_t)cur.dk_ndrive, sizeof(u_int64_t)); |
505 |
|
|
last.dk_wbytes = calloc((size_t)cur.dk_ndrive, sizeof(u_int64_t)); |
506 |
|
|
|
507 |
|
|
if (!cur.dk_time || !cur.dk_rxfer || !cur.dk_wxfer || !cur.dk_seek || |
508 |
|
|
!cur.dk_rbytes || !cur.dk_wbytes || !cur.dk_select || |
509 |
|
|
!cur.dk_name || !last.dk_time || !last.dk_rxfer || |
510 |
|
|
!last.dk_wxfer || !last.dk_seek || !last.dk_rbytes || |
511 |
|
|
!last.dk_wbytes) |
512 |
|
|
errx(1, "Memory allocation failure."); |
513 |
|
|
|
514 |
|
|
/* Set up the compatibility interfaces. */ |
515 |
|
|
dk_ndrive = cur.dk_ndrive; |
516 |
|
|
dk_select = cur.dk_select; |
517 |
|
|
dr_name = cur.dk_name; |
518 |
|
|
|
519 |
|
|
/* Read the disk names and set initial selection. */ |
520 |
|
|
if (nlistf == NULL && memf == NULL) { |
521 |
|
|
mib[0] = CTL_HW; |
522 |
|
|
mib[1] = HW_DISKNAMES; |
523 |
|
|
size = 0; |
524 |
|
|
if (sysctl(mib, 2, NULL, &size, NULL, 0) < 0) |
525 |
|
|
err(1, "can't get hw.disknames"); |
526 |
|
|
disknames = malloc(size); |
527 |
|
|
if (disknames == NULL) |
528 |
|
|
err(1, NULL); |
529 |
|
|
if (sysctl(mib, 2, disknames, &size, NULL, 0) < 0) |
530 |
|
|
err(1, "can't get hw.disknames"); |
531 |
|
|
bufpp = disknames; |
532 |
|
|
for (i = 0; i < dk_ndrive && (name = strsep(&bufpp, ",")) != NULL; i++) { |
533 |
|
|
cur.dk_name[i] = name; |
534 |
|
|
cur.dk_select[i] = sel; |
535 |
|
|
} |
536 |
|
|
for (i = 0; i < dk_ndrive; i++) { |
537 |
|
|
char *p = strchr(cur.dk_name[i], ':'); |
538 |
|
|
if (p) |
539 |
|
|
*p = '\0'; |
540 |
|
|
} |
541 |
|
|
} else { |
542 |
|
|
#if !defined(NOKVM) |
543 |
|
|
p = dk_drivehead; |
544 |
|
|
for (i = 0; i < cur.dk_ndrive; i++) { |
545 |
|
|
char buf[10]; |
546 |
|
|
|
547 |
|
|
deref_kptr(p, &cur_disk, sizeof(cur_disk)); |
548 |
|
|
deref_kptr(cur_disk.dk_name, buf, sizeof(buf)); |
549 |
|
|
cur.dk_name[i] = strdup(buf); |
550 |
|
|
if (!cur.dk_name[i]) |
551 |
|
|
errx(1, "Memory allocation failure."); |
552 |
|
|
cur.dk_select[i] = sel; |
553 |
|
|
|
554 |
|
|
p = TAILQ_NEXT(&cur_disk, dk_link); |
555 |
|
|
} |
556 |
|
|
#endif /* !defined(NOKVM) */ |
557 |
|
|
} |
558 |
|
|
|
559 |
|
|
/* Never do this initialization again. */ |
560 |
|
|
once = 1; |
561 |
|
|
return(1); |
562 |
|
|
} |
563 |
|
|
|
564 |
|
|
#if !defined(NOKVM) |
565 |
|
|
/* |
566 |
|
|
* Dereference the kernel pointer `kptr' and fill in the local copy |
567 |
|
|
* pointed to by `ptr'. The storage space must be pre-allocated, |
568 |
|
|
* and the size of the copy passed in `len'. |
569 |
|
|
*/ |
570 |
|
|
static void |
571 |
|
|
deref_kptr(void *kptr, void *ptr, size_t len) |
572 |
|
|
{ |
573 |
|
|
char buf[128]; |
574 |
|
|
|
575 |
|
|
if (kvm_read(kd, (u_long)kptr, ptr, len) != len) { |
576 |
|
|
memset(buf, 0, sizeof(buf)); |
577 |
|
|
snprintf(buf, (sizeof(buf) - 1), |
578 |
|
|
"can't dereference kptr 0x%lx", (u_long)kptr); |
579 |
|
|
KVM_ERROR(buf); |
580 |
|
|
} |
581 |
|
|
} |
582 |
|
|
#endif /* !defined(NOKVM) */ |