1 /* $NetBSD: subr_iostat.c,v 1.18 2009/09/16 15:23:04 pooka Exp $ */
2 /* NetBSD: subr_disk.c,v 1.69 2005/05/29 22:24:15 christos Exp */
5 * Copyright (c) 1996, 1997, 1999, 2000, 2009 The NetBSD Foundation, Inc.
8 * This code is derived from software contributed to The NetBSD Foundation
9 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
10 * NASA Ames Research Center.
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
21 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
35 * Copyright (c) 1982, 1986, 1988, 1993
36 * The Regents of the University of California. All rights reserved.
37 * (c) UNIX System Laboratories, Inc.
38 * All or some portions of this file are derived from material licensed
39 * to the University of California by American Telephone and Telegraph
40 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
41 * the permission of UNIX System Laboratories, Inc.
43 * Redistribution and use in source and binary forms, with or without
44 * modification, are permitted provided that the following conditions
46 * 1. Redistributions of source code must retain the above copyright
47 * notice, this list of conditions and the following disclaimer.
48 * 2. Redistributions in binary form must reproduce the above copyright
49 * notice, this list of conditions and the following disclaimer in the
50 * documentation and/or other materials provided with the distribution.
51 * 3. Neither the name of the University nor the names of its contributors
52 * may be used to endorse or promote products derived from this software
53 * without specific prior written permission.
55 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
56 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
57 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
58 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
59 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
60 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
61 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
62 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
63 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
64 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
67 * @(#)ufs_disksubr.c 8.5 (Berkeley) 1/21/94
70 #include <sys/cdefs.h>
71 __KERNEL_RCSID(0, "$NetBSD: subr_iostat.c,v 1.18 2009/09/16 15:23:04 pooka Exp $");
73 #include <sys/param.h>
74 #include <sys/kernel.h>
76 #include <sys/iostat.h>
77 #include <sys/sysctl.h>
78 #include <sys/rwlock.h>
81 * Function prototypes for sysctl nodes
83 static int sysctl_hw_disknames(SYSCTLFN_PROTO
);
84 static int sysctl_hw_iostatnames(SYSCTLFN_PROTO
);
85 static int sysctl_hw_iostats(SYSCTLFN_PROTO
);
88 iostati_getnames(int disk_only
, char *oldp
, size_t *oldlenp
, const void *newp
,
92 * A global list of all drives attached to the system. May grow or
95 struct iostatlist_head iostatlist
= TAILQ_HEAD_INITIALIZER(iostatlist
);
96 int iostat_count
; /* number of drives in global drivelist */
97 krwlock_t iostatlist_lock
;
99 static void sysctl_io_stats_setup(struct sysctllog
**);
102 * Initialise the iostat subsystem.
108 rw_init(&iostatlist_lock
);
109 sysctl_io_stats_setup(NULL
);
113 * Searches the iostatlist for the iostat corresponding to the
117 iostat_find(const char *name
)
119 struct io_stats
*iostatp
;
121 KASSERT(name
!= NULL
);
123 rw_enter(&iostatlist_lock
, RW_READER
);
124 TAILQ_FOREACH(iostatp
, &iostatlist
, io_link
) {
125 if (strcmp(iostatp
->io_name
, name
) == 0) {
129 rw_exit(&iostatlist_lock
);
135 * Allocate and initialise memory for the i/o statistics.
138 iostat_alloc(int32_t type
, void *parent
, const char *name
)
140 struct io_stats
*stats
;
142 stats
= kmem_zalloc(sizeof(*stats
), KM_SLEEP
);
144 panic("iostat_alloc: cannot allocate memory for stats buffer");
146 stats
->io_type
= type
;
147 stats
->io_parent
= parent
;
148 (void)strlcpy(stats
->io_name
, name
, sizeof(stats
->io_name
));
151 * Set the attached timestamp.
153 getmicrouptime(&stats
->io_attachtime
);
156 * Link into the drivelist.
158 rw_enter(&iostatlist_lock
, RW_WRITER
);
159 TAILQ_INSERT_TAIL(&iostatlist
, stats
, io_link
);
161 rw_exit(&iostatlist_lock
);
167 * Remove i/o from stats collection.
170 iostat_free(struct io_stats
*stats
)
174 * Remove from the iostat list.
176 if (iostat_count
== 0)
177 panic("iostat_free: iostat_count == 0");
178 rw_enter(&iostatlist_lock
, RW_WRITER
);
179 TAILQ_REMOVE(&iostatlist
, stats
, io_link
);
181 rw_exit(&iostatlist_lock
);
182 kmem_free(stats
, sizeof(*stats
));
186 * Increment a iostat busy counter. If the counter is going from
187 * 0 to 1, set the timestamp.
190 iostat_busy(struct io_stats
*stats
)
193 if (stats
->io_busy
++ == 0)
194 getmicrouptime(&stats
->io_timestamp
);
198 * Decrement a iostat busy counter, increment the byte count, total busy
199 * time, and reset the timestamp.
202 iostat_unbusy(struct io_stats
*stats
, long bcount
, int read
)
204 struct timeval dv_time
, diff_time
;
206 if (stats
->io_busy
-- == 0) {
207 printf("%s: busy < 0\n", stats
->io_name
);
208 panic("iostat_unbusy");
211 getmicrouptime(&dv_time
);
213 timersub(&dv_time
, &stats
->io_timestamp
, &diff_time
);
214 timeradd(&stats
->io_time
, &diff_time
, &stats
->io_time
);
216 stats
->io_timestamp
= dv_time
;
219 stats
->io_rbytes
+= bcount
;
222 stats
->io_wbytes
+= bcount
;
229 * Return non-zero if a device has an I/O request in flight.
232 iostat_isbusy(struct io_stats
*stats
)
235 return stats
->io_busy
!= 0;
239 * Increment the seek counter. This does look almost redundant but it
240 * abstracts the stats gathering.
243 iostat_seek(struct io_stats
*stats
)
250 sysctl_hw_disknames(SYSCTLFN_ARGS
)
253 return iostati_getnames(1, oldp
, oldlenp
, newp
, namelen
);
257 sysctl_hw_iostatnames(SYSCTLFN_ARGS
)
260 return iostati_getnames(0, oldp
, oldlenp
, newp
, namelen
);
264 iostati_getnames(int disk_only
, char *oldp
, size_t *oldlenp
, const void *newp
,
267 char bf
[IOSTATNAMELEN
+ 1];
269 struct io_stats
*stats
;
270 size_t needed
, left
, slen
;
283 rw_enter(&iostatlist_lock
, RW_READER
);
284 for (stats
= TAILQ_FIRST(&iostatlist
); stats
!= NULL
;
285 stats
= TAILQ_NEXT(stats
, io_link
)) {
286 if ((disk_only
== 1) && (stats
->io_type
!= IOSTAT_DISK
))
290 needed
+= strlen(stats
->io_name
) + 1;
292 memset(bf
, 0, sizeof(bf
));
294 strncpy(bf
, stats
->io_name
, sizeof(bf
));
298 strncpy(bf
+ 1, stats
->io_name
,
301 bf
[IOSTATNAMELEN
] = '\0';
305 /* +1 to copy out the trailing NUL byte */
306 error
= copyout(bf
, where
, slen
+ 1);
314 rw_exit(&iostatlist_lock
);
320 sysctl_hw_iostats(SYSCTLFN_ARGS
)
322 struct io_sysctl sdrive
;
323 struct io_stats
*stats
;
332 * The original hw.diskstats call was broken and did not require
333 * the userland to pass in it's size of struct disk_sysctl. This
334 * was fixed after NetBSD 1.6 was released.
337 tocopy
= offsetof(struct io_sysctl
, busy
);
342 *oldlenp
= iostat_count
* tocopy
;
348 memset(&sdrive
, 0, sizeof(sdrive
));
351 rw_enter(&iostatlist_lock
, RW_READER
);
352 TAILQ_FOREACH(stats
, &iostatlist
, io_link
) {
355 strncpy(sdrive
.name
, stats
->io_name
, sizeof(sdrive
.name
));
356 sdrive
.xfer
= stats
->io_rxfer
+ stats
->io_wxfer
;
357 sdrive
.rxfer
= stats
->io_rxfer
;
358 sdrive
.wxfer
= stats
->io_wxfer
;
359 sdrive
.seek
= stats
->io_seek
;
360 sdrive
.bytes
= stats
->io_rbytes
+ stats
->io_wbytes
;
361 sdrive
.rbytes
= stats
->io_rbytes
;
362 sdrive
.wbytes
= stats
->io_wbytes
;
363 sdrive
.attachtime_sec
= stats
->io_attachtime
.tv_sec
;
364 sdrive
.attachtime_usec
= stats
->io_attachtime
.tv_usec
;
365 sdrive
.timestamp_sec
= stats
->io_timestamp
.tv_sec
;
366 sdrive
.timestamp_usec
= stats
->io_timestamp
.tv_usec
;
367 sdrive
.time_sec
= stats
->io_time
.tv_sec
;
368 sdrive
.time_usec
= stats
->io_time
.tv_usec
;
369 sdrive
.busy
= stats
->io_busy
;
371 error
= copyout(&sdrive
, where
, min(tocopy
, sizeof(sdrive
)));
378 rw_exit(&iostatlist_lock
);
383 sysctl_io_stats_setup(struct sysctllog
**clog
)
386 sysctl_createv(clog
, 0, NULL
, NULL
,
388 CTLTYPE_NODE
, "hw", NULL
,
392 sysctl_createv(clog
, 0, NULL
, NULL
,
394 CTLTYPE_STRING
, "disknames",
395 SYSCTL_DESCR("List of disk drives present"),
396 sysctl_hw_disknames
, 0, NULL
, 0,
397 CTL_HW
, HW_DISKNAMES
, CTL_EOL
);
398 sysctl_createv(clog
, 0, NULL
, NULL
,
400 CTLTYPE_STRING
, "iostatnames",
401 SYSCTL_DESCR("I/O stats are being collected for these"
403 sysctl_hw_iostatnames
, 0, NULL
, 0,
404 CTL_HW
, HW_IOSTATNAMES
, CTL_EOL
);
405 sysctl_createv(clog
, 0, NULL
, NULL
,
407 CTLTYPE_STRUCT
, "iostats",
408 SYSCTL_DESCR("Statistics on device I/O operations"),
409 sysctl_hw_iostats
, 0, NULL
, 0,
410 CTL_HW
, HW_IOSTATS
, CTL_EOL
);