1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC. 4 * Copyright (C) 2007 The Regents of the University of California. 5 * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER). 6 * Written by Brian Behlendorf <behlendorf1@llnl.gov>. 7 * UCRL-CODE-235197 8 * 9 * This file is part of the SPL, Solaris Porting Layer. 10 * 11 * The SPL is free software; you can redistribute it and/or modify it 12 * under the terms of the GNU General Public License as published by the 13 * Free Software Foundation; either version 2 of the License, or (at your 14 * option) any later version. 15 * 16 * The SPL is distributed in the hope that it will be useful, but WITHOUT 17 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 18 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 19 * for more details. 20 * 21 * You should have received a copy of the GNU General Public License along 22 * with the SPL. If not, see <http://www.gnu.org/licenses/>. 23 * 24 * Solaris Porting Layer (SPL) Kstat Implementation. 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 * Copyright (c) 2024-2025, Klara, Inc. 32 * Copyright (c) 2024-2025, Syneto 33 */ 34 35 #include <linux/seq_file.h> 36 #include <sys/kstat.h> 37 #include <sys/vmem.h> 38 #include <sys/cmn_err.h> 39 #include <sys/sysmacros.h> 40 #include <sys/string.h> 41 42 static kmutex_t kstat_module_lock; 43 static struct list_head kstat_module_list; 44 static kid_t kstat_id; 45 46 static int 47 kstat_resize_raw(kstat_t *ksp) 48 { 49 if (ksp->ks_raw_bufsize == KSTAT_RAW_MAX) 50 return (ENOMEM); 51 52 vmem_free(ksp->ks_raw_buf, ksp->ks_raw_bufsize); 53 ksp->ks_raw_bufsize = MIN(ksp->ks_raw_bufsize * 2, KSTAT_RAW_MAX); 54 ksp->ks_raw_buf = vmem_alloc(ksp->ks_raw_bufsize, KM_SLEEP); 55 56 return (0); 57 } 58 59 static int 60 kstat_seq_show_headers(struct seq_file *f) 61 { 62 kstat_t *ksp = (kstat_t *)f->private; 63 int rc = 0; 64 65 ASSERT(ksp->ks_magic == KS_MAGIC); 66 67 seq_printf(f, "%d %d 0x%02x %d %d %lld %lld\n", 68 ksp->ks_kid, ksp->ks_type, ksp->ks_flags, 69 ksp->ks_ndata, (int)ksp->ks_data_size, 70 ksp->ks_crtime, ksp->ks_snaptime); 71 72 switch (ksp->ks_type) { 73 case KSTAT_TYPE_RAW: 74 restart: 75 if (ksp->ks_raw_ops.headers) { 76 rc = ksp->ks_raw_ops.headers( 77 ksp->ks_raw_buf, ksp->ks_raw_bufsize); 78 if (rc == ENOMEM && !kstat_resize_raw(ksp)) 79 goto restart; 80 if (!rc) 81 seq_puts(f, ksp->ks_raw_buf); 82 } else { 83 seq_printf(f, "raw data\n"); 84 } 85 break; 86 case KSTAT_TYPE_NAMED: 87 seq_printf(f, "%-31s %-4s %s\n", 88 "name", "type", "data"); 89 break; 90 case KSTAT_TYPE_INTR: 91 seq_printf(f, "%-8s %-8s %-8s %-8s %-8s\n", 92 "hard", "soft", "watchdog", 93 "spurious", "multsvc"); 94 break; 95 case KSTAT_TYPE_IO: 96 seq_printf(f, 97 "%-8s %-8s %-8s %-8s %-8s %-8s " 98 "%-8s %-8s %-8s %-8s %-8s %-8s\n", 99 "nread", "nwritten", "reads", "writes", 100 "wtime", "wlentime", "wupdate", 101 "rtime", "rlentime", "rupdate", 102 "wcnt", "rcnt"); 103 break; 104 case KSTAT_TYPE_TIMER: 105 seq_printf(f, 106 "%-31s %-8s " 107 "%-8s %-8s %-8s %-8s %-8s\n", 108 "name", "events", "elapsed", 109 "min", "max", "start", "stop"); 110 break; 111 default: 112 PANIC("Undefined kstat type %d\n", ksp->ks_type); 113 } 114 115 return (-rc); 116 } 117 118 static int 119 kstat_seq_show_raw(struct seq_file *f, unsigned char *p, int l) 120 { 121 int i, j; 122 123 for (i = 0; ; i++) { 124 seq_printf(f, "%03x:", i); 125 126 for (j = 0; j < 16; j++) { 127 if (i * 16 + j >= l) { 128 seq_printf(f, "\n"); 129 goto out; 130 } 131 132 seq_printf(f, " %02x", (unsigned char)p[i * 16 + j]); 133 } 134 seq_printf(f, "\n"); 135 } 136 out: 137 return (0); 138 } 139 140 static int 141 kstat_seq_show_named(struct seq_file *f, kstat_named_t *knp) 142 { 143 seq_printf(f, "%-31s %-4d ", knp->name, knp->data_type); 144 145 switch (knp->data_type) { 146 case KSTAT_DATA_CHAR: 147 knp->value.c[15] = '\0'; /* NULL terminate */ 148 seq_printf(f, "%-16s", knp->value.c); 149 break; 150 /* 151 * NOTE - We need to be more careful able what tokens are 152 * used for each arch, for now this is correct for x86_64. 153 */ 154 case KSTAT_DATA_INT32: 155 seq_printf(f, "%d", knp->value.i32); 156 break; 157 case KSTAT_DATA_UINT32: 158 seq_printf(f, "%u", knp->value.ui32); 159 break; 160 case KSTAT_DATA_INT64: 161 seq_printf(f, "%lld", (signed long long)knp->value.i64); 162 break; 163 case KSTAT_DATA_UINT64: 164 seq_printf(f, "%llu", 165 (unsigned long long)knp->value.ui64); 166 break; 167 case KSTAT_DATA_LONG: 168 seq_printf(f, "%ld", knp->value.l); 169 break; 170 case KSTAT_DATA_ULONG: 171 seq_printf(f, "%lu", knp->value.ul); 172 break; 173 case KSTAT_DATA_STRING: 174 KSTAT_NAMED_STR_PTR(knp) 175 [KSTAT_NAMED_STR_BUFLEN(knp)-1] = '\0'; 176 seq_printf(f, "%s", KSTAT_NAMED_STR_PTR(knp)); 177 break; 178 default: 179 PANIC("Undefined kstat data type %d\n", knp->data_type); 180 } 181 182 seq_printf(f, "\n"); 183 184 return (0); 185 } 186 187 static int 188 kstat_seq_show_intr(struct seq_file *f, kstat_intr_t *kip) 189 { 190 seq_printf(f, "%-8u %-8u %-8u %-8u %-8u\n", 191 kip->intrs[KSTAT_INTR_HARD], 192 kip->intrs[KSTAT_INTR_SOFT], 193 kip->intrs[KSTAT_INTR_WATCHDOG], 194 kip->intrs[KSTAT_INTR_SPURIOUS], 195 kip->intrs[KSTAT_INTR_MULTSVC]); 196 197 return (0); 198 } 199 200 static int 201 kstat_seq_show_io(struct seq_file *f, kstat_io_t *kip) 202 { 203 /* though wlentime & friends are signed, they will never be negative */ 204 seq_printf(f, 205 "%-8llu %-8llu %-8u %-8u %-8llu %-8llu " 206 "%-8llu %-8llu %-8llu %-8llu %-8u %-8u\n", 207 kip->nread, kip->nwritten, 208 kip->reads, kip->writes, 209 kip->wtime, kip->wlentime, kip->wlastupdate, 210 kip->rtime, kip->rlentime, kip->rlastupdate, 211 kip->wcnt, kip->rcnt); 212 213 return (0); 214 } 215 216 static int 217 kstat_seq_show_timer(struct seq_file *f, kstat_timer_t *ktp) 218 { 219 seq_printf(f, 220 "%-31s %-8llu %-8llu %-8llu %-8llu %-8llu %-8llu\n", 221 ktp->name, ktp->num_events, ktp->elapsed_time, 222 ktp->min_time, ktp->max_time, 223 ktp->start_time, ktp->stop_time); 224 225 return (0); 226 } 227 228 static int 229 kstat_seq_show(struct seq_file *f, void *p) 230 { 231 kstat_t *ksp = (kstat_t *)f->private; 232 int rc = 0; 233 234 ASSERT(ksp->ks_magic == KS_MAGIC); 235 236 switch (ksp->ks_type) { 237 case KSTAT_TYPE_RAW: 238 restart: 239 if (ksp->ks_raw_ops.data) { 240 rc = ksp->ks_raw_ops.data( 241 ksp->ks_raw_buf, ksp->ks_raw_bufsize, p); 242 if (rc == ENOMEM && !kstat_resize_raw(ksp)) 243 goto restart; 244 if (!rc) 245 seq_puts(f, ksp->ks_raw_buf); 246 } else { 247 ASSERT(ksp->ks_ndata == 1); 248 rc = kstat_seq_show_raw(f, ksp->ks_data, 249 ksp->ks_data_size); 250 } 251 break; 252 case KSTAT_TYPE_NAMED: 253 rc = kstat_seq_show_named(f, (kstat_named_t *)p); 254 break; 255 case KSTAT_TYPE_INTR: 256 rc = kstat_seq_show_intr(f, (kstat_intr_t *)p); 257 break; 258 case KSTAT_TYPE_IO: 259 rc = kstat_seq_show_io(f, (kstat_io_t *)p); 260 break; 261 case KSTAT_TYPE_TIMER: 262 rc = kstat_seq_show_timer(f, (kstat_timer_t *)p); 263 break; 264 default: 265 PANIC("Undefined kstat type %d\n", ksp->ks_type); 266 } 267 268 return (-rc); 269 } 270 271 static int 272 kstat_default_update(kstat_t *ksp, int rw) 273 { 274 ASSERT(ksp != NULL); 275 276 if (rw == KSTAT_WRITE) 277 return (EACCES); 278 279 return (0); 280 } 281 282 static void * 283 kstat_seq_data_addr(kstat_t *ksp, loff_t n) 284 { 285 void *rc = NULL; 286 287 switch (ksp->ks_type) { 288 case KSTAT_TYPE_RAW: 289 if (ksp->ks_raw_ops.addr) 290 rc = ksp->ks_raw_ops.addr(ksp, n); 291 else 292 rc = ksp->ks_data; 293 break; 294 case KSTAT_TYPE_NAMED: 295 rc = ksp->ks_data + n * sizeof (kstat_named_t); 296 break; 297 case KSTAT_TYPE_INTR: 298 rc = ksp->ks_data + n * sizeof (kstat_intr_t); 299 break; 300 case KSTAT_TYPE_IO: 301 rc = ksp->ks_data + n * sizeof (kstat_io_t); 302 break; 303 case KSTAT_TYPE_TIMER: 304 rc = ksp->ks_data + n * sizeof (kstat_timer_t); 305 break; 306 default: 307 PANIC("Undefined kstat type %d\n", ksp->ks_type); 308 } 309 310 return (rc); 311 } 312 313 static void * 314 kstat_seq_start(struct seq_file *f, loff_t *pos) 315 { 316 loff_t n = *pos; 317 kstat_t *ksp = (kstat_t *)f->private; 318 ASSERT(ksp->ks_magic == KS_MAGIC); 319 320 mutex_enter(ksp->ks_lock); 321 322 if (ksp->ks_type == KSTAT_TYPE_RAW) { 323 ksp->ks_raw_bufsize = PAGE_SIZE; 324 ksp->ks_raw_buf = vmem_alloc(ksp->ks_raw_bufsize, KM_SLEEP); 325 } 326 327 /* Dynamically update kstat, on error existing kstats are used */ 328 (void) ksp->ks_update(ksp, KSTAT_READ); 329 330 ksp->ks_snaptime = gethrtime(); 331 332 if (!(ksp->ks_flags & KSTAT_FLAG_NO_HEADERS) && !n && 333 kstat_seq_show_headers(f)) 334 return (NULL); 335 336 if (n >= ksp->ks_ndata) 337 return (NULL); 338 339 return (kstat_seq_data_addr(ksp, n)); 340 } 341 342 static void * 343 kstat_seq_next(struct seq_file *f, void *p, loff_t *pos) 344 { 345 kstat_t *ksp = (kstat_t *)f->private; 346 ASSERT(ksp->ks_magic == KS_MAGIC); 347 348 ++*pos; 349 if (*pos >= ksp->ks_ndata) 350 return (NULL); 351 352 return (kstat_seq_data_addr(ksp, *pos)); 353 } 354 355 static void 356 kstat_seq_stop(struct seq_file *f, void *v) 357 { 358 kstat_t *ksp = (kstat_t *)f->private; 359 ASSERT(ksp->ks_magic == KS_MAGIC); 360 361 if (ksp->ks_type == KSTAT_TYPE_RAW) 362 vmem_free(ksp->ks_raw_buf, ksp->ks_raw_bufsize); 363 364 mutex_exit(ksp->ks_lock); 365 } 366 367 static const struct seq_operations kstat_seq_ops = { 368 .show = kstat_seq_show, 369 .start = kstat_seq_start, 370 .next = kstat_seq_next, 371 .stop = kstat_seq_stop, 372 }; 373 374 static kstat_module_t * 375 kstat_find_module(char *name) 376 { 377 ASSERT(MUTEX_HELD(&kstat_module_lock)); 378 379 kstat_module_t *module = NULL; 380 381 list_for_each_entry(module, &kstat_module_list, ksm_module_list) { 382 if (strncmp(name, module->ksm_name, KSTAT_STRLEN) == 0) 383 return (module); 384 } 385 386 return (NULL); 387 } 388 389 static void 390 kstat_delete_module(kstat_module_t *module) 391 { 392 ASSERT(MUTEX_HELD(&kstat_module_lock)); 393 ASSERT(list_empty(&module->ksm_kstat_list)); 394 ASSERT0(module->ksm_nchildren); 395 396 kstat_module_t *parent = module->ksm_parent; 397 398 char *p = module->ksm_name, *frag = NULL; 399 while (p != NULL && (frag = strsep(&p, "/"))) {} 400 401 remove_proc_entry(frag, parent ? parent->ksm_proc : proc_spl_kstat); 402 list_del(&module->ksm_module_list); 403 kmem_free(module, sizeof (kstat_module_t)); 404 405 if (parent) { 406 parent->ksm_nchildren--; 407 if (parent->ksm_nchildren == 0 && 408 list_empty(&parent->ksm_kstat_list)) 409 kstat_delete_module(parent); 410 } 411 } 412 413 static kstat_module_t * 414 kstat_create_module(char *name) 415 { 416 ASSERT(MUTEX_HELD(&kstat_module_lock)); 417 418 char buf[KSTAT_STRLEN]; 419 kstat_module_t *module, *parent; 420 421 (void) strlcpy(buf, name, KSTAT_STRLEN); 422 423 module = parent = NULL; 424 char *p = buf, *frag; 425 while ((frag = strsep(&p, "/")) != NULL) { 426 module = kstat_find_module(buf); 427 if (module == NULL) { 428 struct proc_dir_entry *pde = proc_mkdir(frag, 429 parent ? parent->ksm_proc : proc_spl_kstat); 430 if (pde == NULL) { 431 cmn_err(CE_WARN, "kstat_create('%s'): " 432 "module dir create failed", buf); 433 if (parent) 434 kstat_delete_module(parent); 435 return (NULL); 436 } 437 438 module = kmem_zalloc(sizeof (kstat_module_t), KM_SLEEP); 439 module->ksm_proc = pde; 440 strlcpy(module->ksm_name, buf, KSTAT_STRLEN); 441 INIT_LIST_HEAD(&module->ksm_kstat_list); 442 list_add_tail(&module->ksm_module_list, 443 &kstat_module_list); 444 445 if (parent != NULL) { 446 module->ksm_parent = parent; 447 parent->ksm_nchildren++; 448 } 449 } 450 451 parent = module; 452 if (p != NULL) 453 p[-1] = '/'; 454 } 455 456 return (module); 457 } 458 459 static int 460 proc_kstat_open(struct inode *inode, struct file *filp) 461 { 462 struct seq_file *f; 463 int rc; 464 465 rc = seq_open(filp, &kstat_seq_ops); 466 if (rc) 467 return (rc); 468 469 f = filp->private_data; 470 f->private = SPL_PDE_DATA(inode); 471 472 return (0); 473 } 474 475 static ssize_t 476 proc_kstat_write(struct file *filp, const char __user *buf, size_t len, 477 loff_t *ppos) 478 { 479 struct seq_file *f = filp->private_data; 480 kstat_t *ksp = f->private; 481 int rc; 482 483 ASSERT(ksp->ks_magic == KS_MAGIC); 484 485 mutex_enter(ksp->ks_lock); 486 rc = ksp->ks_update(ksp, KSTAT_WRITE); 487 mutex_exit(ksp->ks_lock); 488 489 if (rc) 490 return (-rc); 491 492 *ppos += len; 493 return (len); 494 } 495 496 static const kstat_proc_op_t proc_kstat_operations = { 497 #ifdef HAVE_PROC_OPS_STRUCT 498 .proc_open = proc_kstat_open, 499 .proc_write = proc_kstat_write, 500 .proc_read = seq_read, 501 .proc_lseek = seq_lseek, 502 .proc_release = seq_release, 503 #else 504 .open = proc_kstat_open, 505 .write = proc_kstat_write, 506 .read = seq_read, 507 .llseek = seq_lseek, 508 .release = seq_release, 509 #endif 510 }; 511 512 void 513 __kstat_set_raw_ops(kstat_t *ksp, 514 int (*headers)(char *buf, size_t size), 515 int (*data)(char *buf, size_t size, void *data), 516 void *(*addr)(kstat_t *ksp, loff_t index)) 517 { 518 ksp->ks_raw_ops.headers = headers; 519 ksp->ks_raw_ops.data = data; 520 ksp->ks_raw_ops.addr = addr; 521 } 522 EXPORT_SYMBOL(__kstat_set_raw_ops); 523 524 void 525 kstat_proc_entry_init(kstat_proc_entry_t *kpep, const char *module, 526 const char *name) 527 { 528 kpep->kpe_owner = NULL; 529 kpep->kpe_proc = NULL; 530 INIT_LIST_HEAD(&kpep->kpe_list); 531 strlcpy(kpep->kpe_module, module, sizeof (kpep->kpe_module)); 532 strlcpy(kpep->kpe_name, name, sizeof (kpep->kpe_name)); 533 } 534 535 kstat_t * 536 __kstat_create(const char *ks_module, int ks_instance, const char *ks_name, 537 const char *ks_class, uchar_t ks_type, uint_t ks_ndata, 538 uchar_t ks_flags) 539 { 540 kstat_t *ksp; 541 542 ASSERT(ks_module); 543 ASSERT0(ks_instance); 544 ASSERT(ks_name); 545 546 if ((ks_type == KSTAT_TYPE_INTR) || (ks_type == KSTAT_TYPE_IO)) 547 ASSERT(ks_ndata == 1); 548 549 ksp = kmem_zalloc(sizeof (*ksp), KM_SLEEP); 550 if (ksp == NULL) 551 return (ksp); 552 553 mutex_enter(&kstat_module_lock); 554 ksp->ks_kid = kstat_id; 555 kstat_id++; 556 mutex_exit(&kstat_module_lock); 557 558 ksp->ks_magic = KS_MAGIC; 559 mutex_init(&ksp->ks_private_lock, NULL, MUTEX_DEFAULT, NULL); 560 ksp->ks_lock = &ksp->ks_private_lock; 561 562 ksp->ks_crtime = gethrtime(); 563 ksp->ks_snaptime = ksp->ks_crtime; 564 ksp->ks_instance = ks_instance; 565 strlcpy(ksp->ks_class, ks_class, sizeof (ksp->ks_class)); 566 ksp->ks_type = ks_type; 567 ksp->ks_flags = ks_flags; 568 ksp->ks_update = kstat_default_update; 569 ksp->ks_private = NULL; 570 ksp->ks_raw_ops.headers = NULL; 571 ksp->ks_raw_ops.data = NULL; 572 ksp->ks_raw_ops.addr = NULL; 573 ksp->ks_raw_buf = NULL; 574 ksp->ks_raw_bufsize = 0; 575 kstat_proc_entry_init(&ksp->ks_proc, ks_module, ks_name); 576 577 switch (ksp->ks_type) { 578 case KSTAT_TYPE_RAW: 579 ksp->ks_ndata = 1; 580 ksp->ks_data_size = ks_ndata; 581 break; 582 case KSTAT_TYPE_NAMED: 583 ksp->ks_ndata = ks_ndata; 584 ksp->ks_data_size = ks_ndata * sizeof (kstat_named_t); 585 break; 586 case KSTAT_TYPE_INTR: 587 ksp->ks_ndata = ks_ndata; 588 ksp->ks_data_size = ks_ndata * sizeof (kstat_intr_t); 589 break; 590 case KSTAT_TYPE_IO: 591 ksp->ks_ndata = ks_ndata; 592 ksp->ks_data_size = ks_ndata * sizeof (kstat_io_t); 593 break; 594 case KSTAT_TYPE_TIMER: 595 ksp->ks_ndata = ks_ndata; 596 ksp->ks_data_size = ks_ndata * sizeof (kstat_timer_t); 597 break; 598 default: 599 PANIC("Undefined kstat type %d\n", ksp->ks_type); 600 } 601 602 if (ksp->ks_flags & KSTAT_FLAG_VIRTUAL) { 603 ksp->ks_data = NULL; 604 } else { 605 ksp->ks_data = kmem_zalloc(ksp->ks_data_size, KM_SLEEP); 606 if (ksp->ks_data == NULL) { 607 kmem_free(ksp, sizeof (*ksp)); 608 ksp = NULL; 609 } 610 } 611 612 return (ksp); 613 } 614 EXPORT_SYMBOL(__kstat_create); 615 616 static int 617 kstat_detect_collision(kstat_proc_entry_t *kpep) 618 { 619 kstat_module_t *module; 620 kstat_proc_entry_t *tmp = NULL; 621 char *parent; 622 char *cp; 623 624 parent = kmem_asprintf("%s", kpep->kpe_module); 625 626 if ((cp = strrchr(parent, '/')) == NULL) { 627 kmem_strfree(parent); 628 return (0); 629 } 630 631 cp[0] = '\0'; 632 if ((module = kstat_find_module(parent)) != NULL) { 633 list_for_each_entry(tmp, &module->ksm_kstat_list, kpe_list) { 634 if (strncmp(tmp->kpe_name, cp+1, KSTAT_STRLEN) == 0) { 635 kmem_strfree(parent); 636 return (EEXIST); 637 } 638 } 639 } 640 641 kmem_strfree(parent); 642 return (0); 643 } 644 645 /* 646 * Add a file to the proc filesystem under the kstat namespace (i.e. 647 * /proc/spl/kstat/). The file need not necessarily be implemented as a 648 * kstat. 649 */ 650 void 651 kstat_proc_entry_install(kstat_proc_entry_t *kpep, mode_t mode, 652 const kstat_proc_op_t *proc_ops, void *data) 653 { 654 kstat_module_t *module; 655 kstat_proc_entry_t *tmp = NULL; 656 657 ASSERT(kpep); 658 659 mutex_enter(&kstat_module_lock); 660 661 module = kstat_find_module(kpep->kpe_module); 662 if (module == NULL) { 663 if (kstat_detect_collision(kpep) != 0) { 664 cmn_err(CE_WARN, "kstat_create('%s', '%s'): namespace" \ 665 " collision", kpep->kpe_module, kpep->kpe_name); 666 goto out; 667 } 668 module = kstat_create_module(kpep->kpe_module); 669 if (module == NULL) 670 goto out; 671 } 672 673 /* 674 * We can only have one entry of this name per module. If one already 675 * exists, replace it by first removing the proc entry, then removing 676 * it from the list. The kstat itself lives on; it just can't be 677 * inspected through the filesystem. 678 */ 679 list_for_each_entry(tmp, &module->ksm_kstat_list, kpe_list) { 680 if (tmp->kpe_proc != NULL && 681 strncmp(tmp->kpe_name, kpep->kpe_name, KSTAT_STRLEN) == 0) { 682 ASSERT3P(tmp->kpe_owner, ==, module); 683 remove_proc_entry(tmp->kpe_name, module->ksm_proc); 684 tmp->kpe_proc = NULL; 685 list_del_init(&tmp->kpe_list); 686 break; 687 } 688 } 689 690 list_add_tail(&kpep->kpe_list, &module->ksm_kstat_list); 691 692 kpep->kpe_owner = module; 693 kpep->kpe_proc = proc_create_data(kpep->kpe_name, mode, 694 module->ksm_proc, proc_ops, data); 695 if (kpep->kpe_proc == NULL) { 696 list_del_init(&kpep->kpe_list); 697 if (list_empty(&module->ksm_kstat_list)) 698 kstat_delete_module(module); 699 } 700 out: 701 mutex_exit(&kstat_module_lock); 702 703 } 704 705 void 706 __kstat_install(kstat_t *ksp) 707 { 708 ASSERT(ksp); 709 mode_t mode; 710 /* Specify permission modes for different kstats */ 711 if (strncmp(ksp->ks_proc.kpe_name, "dbufs", KSTAT_STRLEN) == 0) { 712 mode = 0600; 713 } else { 714 mode = 0644; 715 } 716 kstat_proc_entry_install( 717 &ksp->ks_proc, mode, &proc_kstat_operations, ksp); 718 } 719 EXPORT_SYMBOL(__kstat_install); 720 721 void 722 kstat_proc_entry_delete(kstat_proc_entry_t *kpep) 723 { 724 kstat_module_t *module = kpep->kpe_owner; 725 if (kpep->kpe_proc) 726 remove_proc_entry(kpep->kpe_name, module->ksm_proc); 727 728 mutex_enter(&kstat_module_lock); 729 list_del_init(&kpep->kpe_list); 730 731 /* 732 * Remove top level module directory if it wasn't empty before, but now 733 * is. 734 */ 735 if (kpep->kpe_proc && list_empty(&module->ksm_kstat_list)) 736 kstat_delete_module(module); 737 mutex_exit(&kstat_module_lock); 738 739 } 740 741 void 742 __kstat_delete(kstat_t *ksp) 743 { 744 kstat_proc_entry_delete(&ksp->ks_proc); 745 746 if (!(ksp->ks_flags & KSTAT_FLAG_VIRTUAL)) 747 kmem_free(ksp->ks_data, ksp->ks_data_size); 748 749 ksp->ks_lock = NULL; 750 mutex_destroy(&ksp->ks_private_lock); 751 kmem_free(ksp, sizeof (*ksp)); 752 } 753 EXPORT_SYMBOL(__kstat_delete); 754 755 int 756 spl_kstat_init(void) 757 { 758 mutex_init(&kstat_module_lock, NULL, MUTEX_DEFAULT, NULL); 759 INIT_LIST_HEAD(&kstat_module_list); 760 kstat_id = 0; 761 return (0); 762 } 763 764 void 765 spl_kstat_fini(void) 766 { 767 ASSERT(list_empty(&kstat_module_list)); 768 mutex_destroy(&kstat_module_lock); 769 } 770