1/* 2 * Copyright (c) 2007 Pawel Jakub Dawidek <pjd@FreeBSD.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * Links to Illumos.org for more information on kstat function: 27 * [1] https://illumos.org/man/1M/kstat 28 * [2] https://illumos.org/man/9f/kstat_create 29 */ 30 31#include <sys/cdefs.h> 32__FBSDID("$FreeBSD$"); 33 34#include <sys/types.h> 35#include <sys/param.h> 36#include <sys/kernel.h> 37#include <sys/systm.h> 38#include <sys/malloc.h> 39#include <sys/sysctl.h> 40#include <sys/kstat.h> 41#include <sys/sbuf.h> 42 43static MALLOC_DEFINE(M_KSTAT, "kstat_data", "Kernel statistics"); 44 45SYSCTL_ROOT_NODE(OID_AUTO, kstat, CTLFLAG_RW, 0, "Kernel statistics"); 46 47void 48__kstat_set_raw_ops(kstat_t *ksp, 49 int (*headers)(char *buf, size_t size), 50 int (*data)(char *buf, size_t size, void *data), 51 void *(*addr)(kstat_t *ksp, loff_t index)) 52{ 53 ksp->ks_raw_ops.headers = headers; 54 ksp->ks_raw_ops.data = data; 55 ksp->ks_raw_ops.addr = addr; 56} 57 58void 59__kstat_set_seq_raw_ops(kstat_t *ksp, 60 int (*headers)(struct seq_file *f), 61 int (*data)(char *buf, size_t size, void *data), 62 void *(*addr)(kstat_t *ksp, loff_t index)) 63{ 64 ksp->ks_raw_ops.seq_headers = headers; 65 ksp->ks_raw_ops.data = data; 66 ksp->ks_raw_ops.addr = addr; 67} 68 69static int 70kstat_default_update(kstat_t *ksp, int rw) 71{ 72 ASSERT(ksp != NULL); 73 74 if (rw == KSTAT_WRITE) 75 return (EACCES); 76 77 return (0); 78} 79 80static int 81kstat_resize_raw(kstat_t *ksp) 82{ 83 if (ksp->ks_raw_bufsize == KSTAT_RAW_MAX) 84 return (ENOMEM); 85 86 free(ksp->ks_raw_buf, M_TEMP); 87 ksp->ks_raw_bufsize = MIN(ksp->ks_raw_bufsize * 2, KSTAT_RAW_MAX); 88 ksp->ks_raw_buf = malloc(ksp->ks_raw_bufsize, M_TEMP, M_WAITOK); 89 90 return (0); 91} 92 93static void * 94kstat_raw_default_addr(kstat_t *ksp, loff_t n) 95{ 96 if (n == 0) 97 return (ksp->ks_data); 98 return (NULL); 99} 100 101static int 102kstat_sysctl(SYSCTL_HANDLER_ARGS) 103{ 104 kstat_t *ksp = arg1; 105 kstat_named_t *ksent; 106 uint64_t val; 107 108 ksent = ksp->ks_data; 109 /* Select the correct element */ 110 ksent += arg2; 111 /* Update the aggsums before reading */ 112 (void) ksp->ks_update(ksp, KSTAT_READ); 113 val = ksent->value.ui64; 114 115 return (sysctl_handle_64(oidp, &val, 0, req)); 116} 117 118static int 119kstat_sysctl_string(SYSCTL_HANDLER_ARGS) 120{ 121 kstat_t *ksp = arg1; 122 kstat_named_t *ksent = ksp->ks_data; 123 char *val; 124 uint32_t len = 0; 125 126 /* Select the correct element */ 127 ksent += arg2; 128 /* Update the aggsums before reading */ 129 (void) ksp->ks_update(ksp, KSTAT_READ); 130 val = KSTAT_NAMED_STR_PTR(ksent); 131 len = KSTAT_NAMED_STR_BUFLEN(ksent); 132 val[len-1] = '\0'; 133 134 return (sysctl_handle_string(oidp, val, len, req)); 135} 136 137static int 138kstat_sysctl_io(SYSCTL_HANDLER_ARGS) 139{ 140 struct sbuf *sb; 141 kstat_t *ksp = arg1; 142 kstat_io_t *kip = ksp->ks_data; 143 int rc; 144 145 sb = sbuf_new_auto(); 146 if (sb == NULL) 147 return (ENOMEM); 148 /* Update the aggsums before reading */ 149 (void) ksp->ks_update(ksp, KSTAT_READ); 150 151 /* though wlentime & friends are signed, they will never be negative */ 152 sbuf_printf(sb, 153 "%-8llu %-8llu %-8u %-8u %-8llu %-8llu " 154 "%-8llu %-8llu %-8llu %-8llu %-8u %-8u\n", 155 kip->nread, kip->nwritten, 156 kip->reads, kip->writes, 157 kip->wtime, kip->wlentime, kip->wlastupdate, 158 kip->rtime, kip->rlentime, kip->rlastupdate, 159 kip->wcnt, kip->rcnt); 160 rc = sbuf_finish(sb); 161 if (rc == 0) 162 rc = SYSCTL_OUT(req, sbuf_data(sb), sbuf_len(sb)); 163 sbuf_delete(sb); 164 return (rc); 165} 166 167static int 168kstat_sysctl_raw(SYSCTL_HANDLER_ARGS) 169{ 170 struct sbuf *sb; 171 void *data; 172 kstat_t *ksp = arg1; 173 void *(*addr_op)(kstat_t *ksp, loff_t index); 174 int n, has_header, rc = 0; 175 176 sb = sbuf_new_auto(); 177 if (sb == NULL) 178 return (ENOMEM); 179 180 if (ksp->ks_raw_ops.addr) 181 addr_op = ksp->ks_raw_ops.addr; 182 else 183 addr_op = kstat_raw_default_addr; 184 185 mutex_enter(ksp->ks_lock); 186 187 /* Update the aggsums before reading */ 188 (void) ksp->ks_update(ksp, KSTAT_READ); 189 190 ksp->ks_raw_bufsize = PAGE_SIZE; 191 ksp->ks_raw_buf = malloc(PAGE_SIZE, M_TEMP, M_WAITOK); 192 193 n = 0; 194 has_header = (ksp->ks_raw_ops.headers || 195 ksp->ks_raw_ops.seq_headers); 196 197restart_headers: 198 if (ksp->ks_raw_ops.headers) { 199 rc = ksp->ks_raw_ops.headers( 200 ksp->ks_raw_buf, ksp->ks_raw_bufsize); 201 } else if (ksp->ks_raw_ops.seq_headers) { 202 struct seq_file f; 203 204 f.sf_buf = ksp->ks_raw_buf; 205 f.sf_size = ksp->ks_raw_bufsize; 206 rc = ksp->ks_raw_ops.seq_headers(&f); 207 } 208 if (has_header) { 209 if (rc == ENOMEM && !kstat_resize_raw(ksp)) 210 goto restart_headers; 211 if (rc == 0) 212 sbuf_printf(sb, "\n%s", ksp->ks_raw_buf); 213 } 214 215 while ((data = addr_op(ksp, n)) != NULL) { 216restart: 217 if (ksp->ks_raw_ops.data) { 218 rc = ksp->ks_raw_ops.data(ksp->ks_raw_buf, 219 ksp->ks_raw_bufsize, data); 220 if (rc == ENOMEM && !kstat_resize_raw(ksp)) 221 goto restart; 222 if (rc == 0) 223 sbuf_printf(sb, "%s", ksp->ks_raw_buf); 224 225 } else { 226 ASSERT(ksp->ks_ndata == 1); 227 sbuf_hexdump(sb, ksp->ks_data, 228 ksp->ks_data_size, NULL, 0); 229 } 230 n++; 231 } 232 free(ksp->ks_raw_buf, M_TEMP); 233 mutex_exit(ksp->ks_lock); 234 sbuf_trim(sb); 235 rc = sbuf_finish(sb); 236 if (rc == 0) 237 rc = SYSCTL_OUT(req, sbuf_data(sb), sbuf_len(sb)); 238 sbuf_delete(sb); 239 return (rc); 240} 241 242kstat_t * 243__kstat_create(const char *module, int instance, const char *name, 244 const char *class, uchar_t ks_type, uint_t ks_ndata, uchar_t flags) 245{ 246 char buf[KSTAT_STRLEN]; 247 struct sysctl_oid *root; 248 kstat_t *ksp; 249 char *pool; 250 251 KASSERT(instance == 0, ("instance=%d", instance)); 252 if ((ks_type == KSTAT_TYPE_INTR) || (ks_type == KSTAT_TYPE_IO)) 253 ASSERT(ks_ndata == 1); 254 255 if (class == NULL) 256 class = "misc"; 257 258 /* 259 * Allocate the main structure. We don't need to keep a copy of 260 * module in here, because it is only used for sysctl node creation 261 * done in this function. 262 */ 263 ksp = malloc(sizeof (*ksp), M_KSTAT, M_WAITOK|M_ZERO); 264 265 ksp->ks_crtime = gethrtime(); 266 ksp->ks_snaptime = ksp->ks_crtime; 267 ksp->ks_instance = instance; 268 (void) strlcpy(ksp->ks_name, name, KSTAT_STRLEN); 269 (void) strlcpy(ksp->ks_class, class, KSTAT_STRLEN); 270 ksp->ks_type = ks_type; 271 ksp->ks_flags = flags; 272 ksp->ks_update = kstat_default_update; 273 274 mutex_init(&ksp->ks_private_lock, NULL, MUTEX_DEFAULT, NULL); 275 ksp->ks_lock = &ksp->ks_private_lock; 276 277 switch (ksp->ks_type) { 278 case KSTAT_TYPE_RAW: 279 ksp->ks_ndata = 1; 280 ksp->ks_data_size = ks_ndata; 281 break; 282 case KSTAT_TYPE_NAMED: 283 ksp->ks_ndata = ks_ndata; 284 ksp->ks_data_size = ks_ndata * sizeof (kstat_named_t); 285 break; 286 case KSTAT_TYPE_INTR: 287 ksp->ks_ndata = ks_ndata; 288 ksp->ks_data_size = ks_ndata * sizeof (kstat_intr_t); 289 break; 290 case KSTAT_TYPE_IO: 291 ksp->ks_ndata = ks_ndata; 292 ksp->ks_data_size = ks_ndata * sizeof (kstat_io_t); 293 break; 294 case KSTAT_TYPE_TIMER: 295 ksp->ks_ndata = ks_ndata; 296 ksp->ks_data_size = ks_ndata * sizeof (kstat_timer_t); 297 break; 298 default: 299 panic("Undefined kstat type %d\n", ksp->ks_type); 300 } 301 302 if (ksp->ks_flags & KSTAT_FLAG_VIRTUAL) 303 ksp->ks_data = NULL; 304 else 305 ksp->ks_data = kmem_zalloc(ksp->ks_data_size, KM_SLEEP); 306 307 /* 308 * Some kstats use a module name like "zfs/poolname" to distinguish a 309 * set of kstats belonging to a specific pool. Split on '/' to add an 310 * extra node for the pool name if needed. 311 */ 312 (void) strlcpy(buf, module, KSTAT_STRLEN); 313 module = buf; 314 pool = strchr(module, '/'); 315 if (pool != NULL) 316 *pool++ = '\0'; 317 318 /* 319 * Create sysctl tree for those statistics: 320 * 321 * kstat.<module>[.<pool>].<class>.<name> 322 */ 323 sysctl_ctx_init(&ksp->ks_sysctl_ctx); 324 root = SYSCTL_ADD_NODE(&ksp->ks_sysctl_ctx, 325 SYSCTL_STATIC_CHILDREN(_kstat), OID_AUTO, module, CTLFLAG_RW, 0, 326 ""); 327 if (root == NULL) { 328 printf("%s: Cannot create kstat.%s tree!\n", __func__, module); 329 sysctl_ctx_free(&ksp->ks_sysctl_ctx); 330 free(ksp, M_KSTAT); 331 return (NULL); 332 } 333 if (pool != NULL) { 334 root = SYSCTL_ADD_NODE(&ksp->ks_sysctl_ctx, 335 SYSCTL_CHILDREN(root), OID_AUTO, pool, CTLFLAG_RW, 0, ""); 336 if (root == NULL) { 337 printf("%s: Cannot create kstat.%s.%s tree!\n", 338 __func__, module, pool); 339 sysctl_ctx_free(&ksp->ks_sysctl_ctx); 340 free(ksp, M_KSTAT); 341 return (NULL); 342 } 343 } 344 root = SYSCTL_ADD_NODE(&ksp->ks_sysctl_ctx, SYSCTL_CHILDREN(root), 345 OID_AUTO, class, CTLFLAG_RW, 0, ""); 346 if (root == NULL) { 347 if (pool != NULL) 348 printf("%s: Cannot create kstat.%s.%s.%s tree!\n", 349 __func__, module, pool, class); 350 else 351 printf("%s: Cannot create kstat.%s.%s tree!\n", 352 __func__, module, class); 353 sysctl_ctx_free(&ksp->ks_sysctl_ctx); 354 free(ksp, M_KSTAT); 355 return (NULL); 356 } 357 if (ksp->ks_type == KSTAT_TYPE_NAMED) { 358 root = SYSCTL_ADD_NODE(&ksp->ks_sysctl_ctx, 359 SYSCTL_CHILDREN(root), 360 OID_AUTO, name, CTLFLAG_RW, 0, ""); 361 if (root == NULL) { 362 if (pool != NULL) 363 printf("%s: Cannot create kstat.%s.%s.%s.%s " 364 "tree!\n", __func__, module, pool, class, 365 name); 366 else 367 printf("%s: Cannot create kstat.%s.%s.%s " 368 "tree!\n", __func__, module, class, name); 369 sysctl_ctx_free(&ksp->ks_sysctl_ctx); 370 free(ksp, M_KSTAT); 371 return (NULL); 372 } 373 374 } 375 ksp->ks_sysctl_root = root; 376 377 return (ksp); 378} 379 380static void 381kstat_install_named(kstat_t *ksp) 382{ 383 kstat_named_t *ksent; 384 char *namelast; 385 int typelast; 386 387 ksent = ksp->ks_data; 388 389 VERIFY((ksp->ks_flags & KSTAT_FLAG_VIRTUAL) || ksent != NULL); 390 391 typelast = 0; 392 namelast = NULL; 393 394 for (int i = 0; i < ksp->ks_ndata; i++, ksent++) { 395 if (ksent->data_type != 0) { 396 typelast = ksent->data_type; 397 namelast = ksent->name; 398 } 399 switch (typelast) { 400 case KSTAT_DATA_CHAR: 401 /* Not Implemented */ 402 break; 403 case KSTAT_DATA_INT32: 404 SYSCTL_ADD_PROC(&ksp->ks_sysctl_ctx, 405 SYSCTL_CHILDREN(ksp->ks_sysctl_root), 406 OID_AUTO, namelast, 407 CTLTYPE_S32 | CTLFLAG_RD | CTLFLAG_MPSAFE, 408 ksp, i, kstat_sysctl, "I", namelast); 409 break; 410 case KSTAT_DATA_UINT32: 411 SYSCTL_ADD_PROC(&ksp->ks_sysctl_ctx, 412 SYSCTL_CHILDREN(ksp->ks_sysctl_root), 413 OID_AUTO, namelast, 414 CTLTYPE_U32 | CTLFLAG_RD | CTLFLAG_MPSAFE, 415 ksp, i, kstat_sysctl, "IU", namelast); 416 break; 417 case KSTAT_DATA_INT64: 418 SYSCTL_ADD_PROC(&ksp->ks_sysctl_ctx, 419 SYSCTL_CHILDREN(ksp->ks_sysctl_root), 420 OID_AUTO, namelast, 421 CTLTYPE_S64 | CTLFLAG_RD | CTLFLAG_MPSAFE, 422 ksp, i, kstat_sysctl, "Q", namelast); 423 break; 424 case KSTAT_DATA_UINT64: 425 SYSCTL_ADD_PROC(&ksp->ks_sysctl_ctx, 426 SYSCTL_CHILDREN(ksp->ks_sysctl_root), 427 OID_AUTO, namelast, 428 CTLTYPE_U64 | CTLFLAG_RD | CTLFLAG_MPSAFE, 429 ksp, i, kstat_sysctl, "QU", namelast); 430 break; 431 case KSTAT_DATA_LONG: 432 SYSCTL_ADD_PROC(&ksp->ks_sysctl_ctx, 433 SYSCTL_CHILDREN(ksp->ks_sysctl_root), 434 OID_AUTO, namelast, 435 CTLTYPE_LONG | CTLFLAG_RD | CTLFLAG_MPSAFE, 436 ksp, i, kstat_sysctl, "L", namelast); 437 break; 438 case KSTAT_DATA_ULONG: 439 SYSCTL_ADD_PROC(&ksp->ks_sysctl_ctx, 440 SYSCTL_CHILDREN(ksp->ks_sysctl_root), 441 OID_AUTO, namelast, 442 CTLTYPE_ULONG | CTLFLAG_RD | CTLFLAG_MPSAFE, 443 ksp, i, kstat_sysctl, "LU", namelast); 444 break; 445 case KSTAT_DATA_STRING: 446 SYSCTL_ADD_PROC(&ksp->ks_sysctl_ctx, 447 SYSCTL_CHILDREN(ksp->ks_sysctl_root), 448 OID_AUTO, namelast, 449 CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, 450 ksp, i, kstat_sysctl_string, "A", namelast); 451 break; 452 default: 453 panic("unsupported type: %d", typelast); 454 } 455 } 456} 457 458void 459kstat_install(kstat_t *ksp) 460{ 461 struct sysctl_oid *root; 462 463 if (ksp->ks_ndata == UINT32_MAX) 464 VERIFY(ksp->ks_type == KSTAT_TYPE_RAW); 465 466 switch (ksp->ks_type) { 467 case KSTAT_TYPE_NAMED: 468 return (kstat_install_named(ksp)); 469 case KSTAT_TYPE_RAW: 470 if (ksp->ks_raw_ops.data) { 471 root = SYSCTL_ADD_PROC(&ksp->ks_sysctl_ctx, 472 SYSCTL_CHILDREN(ksp->ks_sysctl_root), 473 OID_AUTO, ksp->ks_name, CTLTYPE_STRING | CTLFLAG_RD 474 | CTLFLAG_MPSAFE | CTLFLAG_SKIP, 475 ksp, 0, kstat_sysctl_raw, "A", ksp->ks_name); 476 } else { 477 root = SYSCTL_ADD_PROC(&ksp->ks_sysctl_ctx, 478 SYSCTL_CHILDREN(ksp->ks_sysctl_root), 479 OID_AUTO, ksp->ks_name, CTLTYPE_OPAQUE | CTLFLAG_RD 480 | CTLFLAG_MPSAFE | CTLFLAG_SKIP, 481 ksp, 0, kstat_sysctl_raw, "", ksp->ks_name); 482 } 483 break; 484 case KSTAT_TYPE_IO: 485 root = SYSCTL_ADD_PROC(&ksp->ks_sysctl_ctx, 486 SYSCTL_CHILDREN(ksp->ks_sysctl_root), 487 OID_AUTO, ksp->ks_name, 488 CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, 489 ksp, 0, kstat_sysctl_io, "A", ksp->ks_name); 490 break; 491 case KSTAT_TYPE_TIMER: 492 case KSTAT_TYPE_INTR: 493 default: 494 panic("unsupported kstat type %d\n", ksp->ks_type); 495 } 496 VERIFY(root != NULL); 497 ksp->ks_sysctl_root = root; 498} 499 500void 501kstat_delete(kstat_t *ksp) 502{ 503 504 sysctl_ctx_free(&ksp->ks_sysctl_ctx); 505 ksp->ks_lock = NULL; 506 mutex_destroy(&ksp->ks_private_lock); 507 if (!(ksp->ks_flags & KSTAT_FLAG_VIRTUAL)) 508 kmem_free(ksp->ks_data, ksp->ks_data_size); 509 free(ksp, M_KSTAT); 510} 511