1 1.26 mlelstv /* $NetBSD: subr_iostat.c,v 1.26 2024/05/04 13:33:18 mlelstv Exp $ */ 2 1.1 blymn /* NetBSD: subr_disk.c,v 1.69 2005/05/29 22:24:15 christos Exp */ 3 1.1 blymn 4 1.1 blymn /*- 5 1.17 ad * Copyright (c) 1996, 1997, 1999, 2000, 2009 The NetBSD Foundation, Inc. 6 1.1 blymn * All rights reserved. 7 1.1 blymn * 8 1.1 blymn * This code is derived from software contributed to The NetBSD Foundation 9 1.1 blymn * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 10 1.1 blymn * NASA Ames Research Center. 11 1.1 blymn * 12 1.1 blymn * Redistribution and use in source and binary forms, with or without 13 1.1 blymn * modification, are permitted provided that the following conditions 14 1.1 blymn * are met: 15 1.1 blymn * 1. Redistributions of source code must retain the above copyright 16 1.1 blymn * notice, this list of conditions and the following disclaimer. 17 1.1 blymn * 2. Redistributions in binary form must reproduce the above copyright 18 1.1 blymn * notice, this list of conditions and the following disclaimer in the 19 1.1 blymn * documentation and/or other materials provided with the distribution. 20 1.1 blymn * 21 1.1 blymn * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 22 1.1 blymn * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 23 1.1 blymn * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 1.1 blymn * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 25 1.1 blymn * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 1.1 blymn * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 1.1 blymn * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 1.1 blymn * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 1.1 blymn * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 1.1 blymn * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 1.1 blymn * POSSIBILITY OF SUCH DAMAGE. 32 1.1 blymn */ 33 1.1 blymn 34 1.1 blymn /* 35 1.1 blymn * Copyright (c) 1982, 1986, 1988, 1993 36 1.1 blymn * The Regents of the University of California. All rights reserved. 37 1.1 blymn * (c) UNIX System Laboratories, Inc. 38 1.1 blymn * All or some portions of this file are derived from material licensed 39 1.1 blymn * to the University of California by American Telephone and Telegraph 40 1.1 blymn * Co. or Unix System Laboratories, Inc. and are reproduced herein with 41 1.1 blymn * the permission of UNIX System Laboratories, Inc. 42 1.1 blymn * 43 1.1 blymn * Redistribution and use in source and binary forms, with or without 44 1.1 blymn * modification, are permitted provided that the following conditions 45 1.1 blymn * are met: 46 1.1 blymn * 1. Redistributions of source code must retain the above copyright 47 1.1 blymn * notice, this list of conditions and the following disclaimer. 48 1.1 blymn * 2. Redistributions in binary form must reproduce the above copyright 49 1.1 blymn * notice, this list of conditions and the following disclaimer in the 50 1.1 blymn * documentation and/or other materials provided with the distribution. 51 1.1 blymn * 3. Neither the name of the University nor the names of its contributors 52 1.1 blymn * may be used to endorse or promote products derived from this software 53 1.1 blymn * without specific prior written permission. 54 1.1 blymn * 55 1.1 blymn * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 56 1.1 blymn * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 57 1.1 blymn * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 58 1.1 blymn * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 59 1.1 blymn * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 60 1.1 blymn * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 61 1.1 blymn * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 62 1.1 blymn * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 63 1.1 blymn * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 64 1.1 blymn * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 65 1.1 blymn * SUCH DAMAGE. 66 1.1 blymn * 67 1.1 blymn * @(#)ufs_disksubr.c 8.5 (Berkeley) 1/21/94 68 1.1 blymn */ 69 1.1 blymn 70 1.1 blymn #include <sys/cdefs.h> 71 1.26 mlelstv __KERNEL_RCSID(0, "$NetBSD: subr_iostat.c,v 1.26 2024/05/04 13:33:18 mlelstv Exp $"); 72 1.1 blymn 73 1.1 blymn #include <sys/param.h> 74 1.1 blymn #include <sys/kernel.h> 75 1.16 yamt #include <sys/kmem.h> 76 1.6 yamt #include <sys/iostat.h> 77 1.1 blymn #include <sys/sysctl.h> 78 1.13 ad #include <sys/rwlock.h> 79 1.1 blymn 80 1.1 blymn /* 81 1.1 blymn * Function prototypes for sysctl nodes 82 1.1 blymn */ 83 1.1 blymn static int sysctl_hw_disknames(SYSCTLFN_PROTO); 84 1.1 blymn static int sysctl_hw_iostatnames(SYSCTLFN_PROTO); 85 1.1 blymn static int sysctl_hw_iostats(SYSCTLFN_PROTO); 86 1.1 blymn 87 1.1 blymn static int 88 1.1 blymn iostati_getnames(int disk_only, char *oldp, size_t *oldlenp, const void *newp, 89 1.1 blymn u_int namelen); 90 1.1 blymn 91 1.1 blymn /* 92 1.1 blymn * A global list of all drives attached to the system. May grow or 93 1.1 blymn * shrink over time. 94 1.1 blymn */ 95 1.3 yamt struct iostatlist_head iostatlist = TAILQ_HEAD_INITIALIZER(iostatlist); 96 1.3 yamt int iostat_count; /* number of drives in global drivelist */ 97 1.13 ad krwlock_t iostatlist_lock; 98 1.12 ad 99 1.18 pooka static void sysctl_io_stats_setup(struct sysctllog **); 100 1.18 pooka 101 1.12 ad /* 102 1.12 ad * Initialise the iostat subsystem. 103 1.12 ad */ 104 1.12 ad void 105 1.12 ad iostat_init(void) 106 1.12 ad { 107 1.12 ad 108 1.13 ad rw_init(&iostatlist_lock); 109 1.18 pooka sysctl_io_stats_setup(NULL); 110 1.12 ad } 111 1.1 blymn 112 1.1 blymn /* 113 1.1 blymn * Searches the iostatlist for the iostat corresponding to the 114 1.1 blymn * name provided. 115 1.1 blymn */ 116 1.1 blymn struct io_stats * 117 1.8 yamt iostat_find(const char *name) 118 1.1 blymn { 119 1.1 blymn struct io_stats *iostatp; 120 1.1 blymn 121 1.8 yamt KASSERT(name != NULL); 122 1.1 blymn 123 1.13 ad rw_enter(&iostatlist_lock, RW_READER); 124 1.8 yamt TAILQ_FOREACH(iostatp, &iostatlist, io_link) { 125 1.2 blymn if (strcmp(iostatp->io_name, name) == 0) { 126 1.8 yamt break; 127 1.1 blymn } 128 1.8 yamt } 129 1.13 ad rw_exit(&iostatlist_lock); 130 1.1 blymn 131 1.8 yamt return iostatp; 132 1.1 blymn } 133 1.1 blymn 134 1.1 blymn /* 135 1.1 blymn * Allocate and initialise memory for the i/o statistics. 136 1.1 blymn */ 137 1.3 yamt struct io_stats * 138 1.11 christos iostat_alloc(int32_t type, void *parent, const char *name) 139 1.1 blymn { 140 1.1 blymn struct io_stats *stats; 141 1.1 blymn 142 1.16 yamt stats = kmem_zalloc(sizeof(*stats), KM_SLEEP); 143 1.2 blymn stats->io_type = type; 144 1.11 christos stats->io_parent = parent; 145 1.11 christos (void)strlcpy(stats->io_name, name, sizeof(stats->io_name)); 146 1.1 blymn 147 1.1 blymn /* 148 1.1 blymn * Set the attached timestamp. 149 1.1 blymn */ 150 1.10 kardel getmicrouptime(&stats->io_attachtime); 151 1.1 blymn 152 1.1 blymn /* 153 1.1 blymn * Link into the drivelist. 154 1.1 blymn */ 155 1.13 ad rw_enter(&iostatlist_lock, RW_WRITER); 156 1.2 blymn TAILQ_INSERT_TAIL(&iostatlist, stats, io_link); 157 1.1 blymn iostat_count++; 158 1.13 ad rw_exit(&iostatlist_lock); 159 1.1 blymn 160 1.1 blymn return stats; 161 1.1 blymn } 162 1.1 blymn 163 1.1 blymn /* 164 1.1 blymn * Remove i/o from stats collection. 165 1.1 blymn */ 166 1.1 blymn void 167 1.1 blymn iostat_free(struct io_stats *stats) 168 1.1 blymn { 169 1.1 blymn 170 1.3 yamt /* 171 1.3 yamt * Remove from the iostat list. 172 1.3 yamt */ 173 1.1 blymn if (iostat_count == 0) 174 1.1 blymn panic("iostat_free: iostat_count == 0"); 175 1.13 ad rw_enter(&iostatlist_lock, RW_WRITER); 176 1.2 blymn TAILQ_REMOVE(&iostatlist, stats, io_link); 177 1.1 blymn iostat_count--; 178 1.13 ad rw_exit(&iostatlist_lock); 179 1.16 yamt kmem_free(stats, sizeof(*stats)); 180 1.1 blymn } 181 1.1 blymn 182 1.1 blymn /* 183 1.25 hannken * Rename i/o stats. 184 1.25 hannken */ 185 1.25 hannken void 186 1.25 hannken iostat_rename(struct io_stats *stats, const char *name) 187 1.25 hannken { 188 1.25 hannken 189 1.25 hannken rw_enter(&iostatlist_lock, RW_WRITER); 190 1.25 hannken (void)strlcpy(stats->io_name, name, sizeof(stats->io_name)); 191 1.25 hannken rw_exit(&iostatlist_lock); 192 1.25 hannken } 193 1.25 hannken 194 1.25 hannken /* 195 1.22 mlelstv * multiply timeval by unsigned integer and add to result 196 1.22 mlelstv */ 197 1.22 mlelstv static void 198 1.22 mlelstv timermac(struct timeval *a, uint64_t count, struct timeval *res) 199 1.22 mlelstv { 200 1.22 mlelstv struct timeval part = *a; 201 1.22 mlelstv 202 1.22 mlelstv while (count) { 203 1.22 mlelstv if (count & 1) 204 1.22 mlelstv timeradd(res, &part, res); 205 1.22 mlelstv timeradd(&part, &part, &part); 206 1.22 mlelstv count >>= 1; 207 1.22 mlelstv } 208 1.22 mlelstv } 209 1.22 mlelstv 210 1.22 mlelstv /* 211 1.22 mlelstv * Increment the iostat wait counter. 212 1.22 mlelstv * Accumulate wait time and timesum. 213 1.22 mlelstv * 214 1.22 mlelstv * Wait time is spent in the device bufq. 215 1.22 mlelstv */ 216 1.22 mlelstv void 217 1.22 mlelstv iostat_wait(struct io_stats *stats) 218 1.22 mlelstv { 219 1.22 mlelstv struct timeval dv_time, diff_time; 220 1.22 mlelstv int32_t count; 221 1.22 mlelstv 222 1.22 mlelstv KASSERT(stats->io_wait >= 0); 223 1.22 mlelstv 224 1.22 mlelstv getmicrouptime(&dv_time); 225 1.22 mlelstv 226 1.22 mlelstv timersub(&dv_time, &stats->io_waitstamp, &diff_time); 227 1.22 mlelstv count = stats->io_wait++; 228 1.22 mlelstv if (count != 0) { 229 1.22 mlelstv timermac(&diff_time, count, &stats->io_waitsum); 230 1.22 mlelstv timeradd(&stats->io_waittime, &diff_time, &stats->io_waittime); 231 1.22 mlelstv } 232 1.22 mlelstv stats->io_waitstamp = dv_time; 233 1.22 mlelstv } 234 1.22 mlelstv 235 1.22 mlelstv /* 236 1.22 mlelstv * Decrement the iostat wait counter. 237 1.22 mlelstv * Increment the iostat busy counter. 238 1.22 mlelstv * Accumulate wait and busy times and timesums. 239 1.22 mlelstv * 240 1.22 mlelstv * Busy time is spent being processed by the device. 241 1.22 mlelstv * 242 1.22 mlelstv * Old devices do not yet measure wait time, so skip 243 1.22 mlelstv * processing it if the counter is still zero. 244 1.1 blymn */ 245 1.1 blymn void 246 1.1 blymn iostat_busy(struct io_stats *stats) 247 1.1 blymn { 248 1.22 mlelstv struct timeval dv_time, diff_time; 249 1.22 mlelstv int32_t count; 250 1.22 mlelstv 251 1.22 mlelstv KASSERT(stats->io_wait >= 0); /* > 0 when iostat_wait is used */ 252 1.22 mlelstv KASSERT(stats->io_busy >= 0); 253 1.22 mlelstv 254 1.22 mlelstv getmicrouptime(&dv_time); 255 1.1 blymn 256 1.22 mlelstv timersub(&dv_time, &stats->io_waitstamp, &diff_time); 257 1.22 mlelstv if (stats->io_wait != 0) { 258 1.22 mlelstv count = stats->io_wait--; 259 1.22 mlelstv timermac(&diff_time, count, &stats->io_waitsum); 260 1.22 mlelstv timeradd(&stats->io_waittime, &diff_time, &stats->io_waittime); 261 1.22 mlelstv } 262 1.22 mlelstv stats->io_waitstamp = dv_time; 263 1.22 mlelstv 264 1.22 mlelstv timersub(&dv_time, &stats->io_busystamp, &diff_time); 265 1.22 mlelstv count = stats->io_busy++; 266 1.22 mlelstv if (count != 0) { 267 1.22 mlelstv timermac(&diff_time, count, &stats->io_busysum); 268 1.22 mlelstv timeradd(&stats->io_busytime, &diff_time, &stats->io_busytime); 269 1.22 mlelstv } 270 1.22 mlelstv stats->io_busystamp = dv_time; 271 1.1 blymn } 272 1.1 blymn 273 1.1 blymn /* 274 1.22 mlelstv * Decrement the iostat busy counter, increment the byte count. 275 1.22 mlelstv * Accumulate busy time and timesum. 276 1.1 blymn */ 277 1.1 blymn void 278 1.1 blymn iostat_unbusy(struct io_stats *stats, long bcount, int read) 279 1.1 blymn { 280 1.1 blymn struct timeval dv_time, diff_time; 281 1.22 mlelstv int32_t count; 282 1.1 blymn 283 1.22 mlelstv KASSERT(stats->io_busy > 0); 284 1.1 blymn 285 1.10 kardel getmicrouptime(&dv_time); 286 1.22 mlelstv stats->io_timestamp = dv_time; 287 1.1 blymn 288 1.22 mlelstv /* any op */ 289 1.22 mlelstv timersub(&dv_time, &stats->io_busystamp, &diff_time); 290 1.22 mlelstv count = stats->io_busy--; 291 1.22 mlelstv timermac(&diff_time, count, &stats->io_busysum); 292 1.22 mlelstv timeradd(&stats->io_busytime, &diff_time, &stats->io_busytime); 293 1.22 mlelstv stats->io_busystamp = dv_time; 294 1.1 blymn 295 1.1 blymn if (bcount > 0) { 296 1.1 blymn if (read) { 297 1.2 blymn stats->io_rbytes += bcount; 298 1.2 blymn stats->io_rxfer++; 299 1.1 blymn } else { 300 1.2 blymn stats->io_wbytes += bcount; 301 1.2 blymn stats->io_wxfer++; 302 1.1 blymn } 303 1.1 blymn } 304 1.1 blymn } 305 1.1 blymn 306 1.1 blymn /* 307 1.17 ad * Return non-zero if a device has an I/O request in flight. 308 1.17 ad */ 309 1.17 ad bool 310 1.17 ad iostat_isbusy(struct io_stats *stats) 311 1.17 ad { 312 1.17 ad 313 1.17 ad return stats->io_busy != 0; 314 1.17 ad } 315 1.17 ad 316 1.17 ad /* 317 1.1 blymn * Increment the seek counter. This does look almost redundant but it 318 1.1 blymn * abstracts the stats gathering. 319 1.1 blymn */ 320 1.1 blymn void 321 1.1 blymn iostat_seek(struct io_stats *stats) 322 1.1 blymn { 323 1.3 yamt 324 1.2 blymn stats->io_seek++; 325 1.1 blymn } 326 1.1 blymn 327 1.1 blymn static int 328 1.1 blymn sysctl_hw_disknames(SYSCTLFN_ARGS) 329 1.1 blymn { 330 1.3 yamt 331 1.1 blymn return iostati_getnames(1, oldp, oldlenp, newp, namelen); 332 1.1 blymn } 333 1.1 blymn 334 1.1 blymn static int 335 1.1 blymn sysctl_hw_iostatnames(SYSCTLFN_ARGS) 336 1.1 blymn { 337 1.3 yamt 338 1.1 blymn return iostati_getnames(0, oldp, oldlenp, newp, namelen); 339 1.1 blymn } 340 1.1 blymn 341 1.1 blymn static int 342 1.1 blymn iostati_getnames(int disk_only, char *oldp, size_t *oldlenp, const void *newp, 343 1.1 blymn u_int namelen) 344 1.1 blymn { 345 1.1 blymn char bf[IOSTATNAMELEN + 1]; 346 1.1 blymn char *where = oldp; 347 1.1 blymn struct io_stats *stats; 348 1.1 blymn size_t needed, left, slen; 349 1.1 blymn int error, first; 350 1.1 blymn 351 1.1 blymn if (newp != NULL) 352 1.1 blymn return (EPERM); 353 1.1 blymn if (namelen != 0) 354 1.1 blymn return (EINVAL); 355 1.1 blymn 356 1.1 blymn first = 1; 357 1.1 blymn error = 0; 358 1.1 blymn needed = 0; 359 1.1 blymn left = *oldlenp; 360 1.1 blymn 361 1.13 ad rw_enter(&iostatlist_lock, RW_READER); 362 1.1 blymn for (stats = TAILQ_FIRST(&iostatlist); stats != NULL; 363 1.2 blymn stats = TAILQ_NEXT(stats, io_link)) { 364 1.2 blymn if ((disk_only == 1) && (stats->io_type != IOSTAT_DISK)) 365 1.1 blymn continue; 366 1.1 blymn 367 1.1 blymn if (where == NULL) 368 1.2 blymn needed += strlen(stats->io_name) + 1; 369 1.1 blymn else { 370 1.1 blymn memset(bf, 0, sizeof(bf)); 371 1.1 blymn if (first) { 372 1.2 blymn strncpy(bf, stats->io_name, sizeof(bf)); 373 1.26 mlelstv /* account for trailing NUL byte */ 374 1.26 mlelstv needed += 1; 375 1.1 blymn first = 0; 376 1.1 blymn } else { 377 1.1 blymn bf[0] = ' '; 378 1.2 blymn strncpy(bf + 1, stats->io_name, 379 1.1 blymn sizeof(bf) - 1); 380 1.1 blymn } 381 1.1 blymn bf[IOSTATNAMELEN] = '\0'; 382 1.1 blymn slen = strlen(bf); 383 1.1 blymn if (left < slen + 1) 384 1.1 blymn break; 385 1.1 blymn /* +1 to copy out the trailing NUL byte */ 386 1.1 blymn error = copyout(bf, where, slen + 1); 387 1.1 blymn if (error) 388 1.1 blymn break; 389 1.1 blymn where += slen; 390 1.1 blymn needed += slen; 391 1.1 blymn left -= slen; 392 1.1 blymn } 393 1.1 blymn } 394 1.13 ad rw_exit(&iostatlist_lock); 395 1.1 blymn *oldlenp = needed; 396 1.1 blymn return (error); 397 1.1 blymn } 398 1.1 blymn 399 1.1 blymn static int 400 1.1 blymn sysctl_hw_iostats(SYSCTLFN_ARGS) 401 1.1 blymn { 402 1.1 blymn struct io_sysctl sdrive; 403 1.1 blymn struct io_stats *stats; 404 1.1 blymn char *where = oldp; 405 1.1 blymn size_t tocopy, left; 406 1.1 blymn int error; 407 1.1 blymn 408 1.1 blymn if (newp != NULL) 409 1.1 blymn return (EPERM); 410 1.1 blymn 411 1.1 blymn /* 412 1.1 blymn * The original hw.diskstats call was broken and did not require 413 1.21 snj * the userland to pass in its size of struct disk_sysctl. This 414 1.15 ad * was fixed after NetBSD 1.6 was released. 415 1.1 blymn */ 416 1.1 blymn if (namelen == 0) 417 1.1 blymn tocopy = offsetof(struct io_sysctl, busy); 418 1.1 blymn else 419 1.1 blymn tocopy = name[0]; 420 1.1 blymn 421 1.1 blymn if (where == NULL) { 422 1.1 blymn *oldlenp = iostat_count * tocopy; 423 1.1 blymn return (0); 424 1.1 blymn } 425 1.1 blymn 426 1.1 blymn error = 0; 427 1.1 blymn left = *oldlenp; 428 1.1 blymn memset(&sdrive, 0, sizeof(sdrive)); 429 1.1 blymn *oldlenp = 0; 430 1.1 blymn 431 1.13 ad rw_enter(&iostatlist_lock, RW_READER); 432 1.2 blymn TAILQ_FOREACH(stats, &iostatlist, io_link) { 433 1.1 blymn if (left < tocopy) 434 1.1 blymn break; 435 1.22 mlelstv 436 1.2 blymn strncpy(sdrive.name, stats->io_name, sizeof(sdrive.name)); 437 1.22 mlelstv sdrive.attachtime_sec = stats->io_attachtime.tv_sec; 438 1.22 mlelstv sdrive.attachtime_usec = stats->io_attachtime.tv_usec; 439 1.22 mlelstv sdrive.timestamp_sec = stats->io_busystamp.tv_sec; 440 1.22 mlelstv sdrive.timestamp_usec = stats->io_busystamp.tv_usec; 441 1.22 mlelstv 442 1.22 mlelstv sdrive.time_sec = stats->io_busytime.tv_sec; 443 1.22 mlelstv sdrive.time_usec = stats->io_busytime.tv_usec; 444 1.22 mlelstv 445 1.22 mlelstv sdrive.seek = stats->io_seek; 446 1.22 mlelstv 447 1.2 blymn sdrive.rxfer = stats->io_rxfer; 448 1.2 blymn sdrive.wxfer = stats->io_wxfer; 449 1.22 mlelstv sdrive.xfer = stats->io_rxfer + stats->io_wxfer; 450 1.22 mlelstv 451 1.2 blymn sdrive.rbytes = stats->io_rbytes; 452 1.2 blymn sdrive.wbytes = stats->io_wbytes; 453 1.22 mlelstv sdrive.bytes = stats->io_rbytes + stats->io_wbytes; 454 1.22 mlelstv 455 1.22 mlelstv sdrive.wait_sec = stats->io_waittime.tv_sec; 456 1.22 mlelstv sdrive.wait_usec = stats->io_waittime.tv_usec; 457 1.22 mlelstv 458 1.22 mlelstv sdrive.time_sec = stats->io_busytime.tv_sec; 459 1.22 mlelstv sdrive.time_usec = stats->io_busytime.tv_usec; 460 1.22 mlelstv 461 1.22 mlelstv sdrive.waitsum_sec = stats->io_waitsum.tv_sec; 462 1.22 mlelstv sdrive.waitsum_usec = stats->io_waitsum.tv_usec; 463 1.22 mlelstv 464 1.22 mlelstv sdrive.busysum_sec = stats->io_busysum.tv_sec; 465 1.22 mlelstv sdrive.busysum_usec = stats->io_busysum.tv_usec; 466 1.22 mlelstv 467 1.2 blymn sdrive.busy = stats->io_busy; 468 1.1 blymn 469 1.24 riastrad error = copyout(&sdrive, where, uimin(tocopy, sizeof(sdrive))); 470 1.1 blymn if (error) 471 1.1 blymn break; 472 1.1 blymn where += tocopy; 473 1.1 blymn *oldlenp += tocopy; 474 1.1 blymn left -= tocopy; 475 1.1 blymn } 476 1.13 ad rw_exit(&iostatlist_lock); 477 1.1 blymn return (error); 478 1.1 blymn } 479 1.1 blymn 480 1.18 pooka static void 481 1.18 pooka sysctl_io_stats_setup(struct sysctllog **clog) 482 1.1 blymn { 483 1.3 yamt 484 1.1 blymn sysctl_createv(clog, 0, NULL, NULL, 485 1.1 blymn CTLFLAG_PERMANENT, 486 1.1 blymn CTLTYPE_STRING, "disknames", 487 1.1 blymn SYSCTL_DESCR("List of disk drives present"), 488 1.1 blymn sysctl_hw_disknames, 0, NULL, 0, 489 1.1 blymn CTL_HW, HW_DISKNAMES, CTL_EOL); 490 1.1 blymn sysctl_createv(clog, 0, NULL, NULL, 491 1.1 blymn CTLFLAG_PERMANENT, 492 1.1 blymn CTLTYPE_STRING, "iostatnames", 493 1.1 blymn SYSCTL_DESCR("I/O stats are being collected for these" 494 1.1 blymn " devices"), 495 1.1 blymn sysctl_hw_iostatnames, 0, NULL, 0, 496 1.1 blymn CTL_HW, HW_IOSTATNAMES, CTL_EOL); 497 1.1 blymn sysctl_createv(clog, 0, NULL, NULL, 498 1.1 blymn CTLFLAG_PERMANENT, 499 1.7 yamt CTLTYPE_STRUCT, "iostats", 500 1.1 blymn SYSCTL_DESCR("Statistics on device I/O operations"), 501 1.1 blymn sysctl_hw_iostats, 0, NULL, 0, 502 1.1 blymn CTL_HW, HW_IOSTATS, CTL_EOL); 503 1.1 blymn } 504