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 EXPORT_SYMBOL(kstat_proc_entry_init); 535 536 kstat_t * 537 __kstat_create(const char *ks_module, int ks_instance, const char *ks_name, 538 const char *ks_class, uchar_t ks_type, uint_t ks_ndata, 539 uchar_t ks_flags) 540 { 541 kstat_t *ksp; 542 543 ASSERT(ks_module); 544 ASSERT(ks_instance == 0); 545 ASSERT(ks_name); 546 547 if ((ks_type == KSTAT_TYPE_INTR) || (ks_type == KSTAT_TYPE_IO)) 548 ASSERT(ks_ndata == 1); 549 550 ksp = kmem_zalloc(sizeof (*ksp), KM_SLEEP); 551 if (ksp == NULL) 552 return (ksp); 553 554 mutex_enter(&kstat_module_lock); 555 ksp->ks_kid = kstat_id; 556 kstat_id++; 557 mutex_exit(&kstat_module_lock); 558 559 ksp->ks_magic = KS_MAGIC; 560 mutex_init(&ksp->ks_private_lock, NULL, MUTEX_DEFAULT, NULL); 561 ksp->ks_lock = &ksp->ks_private_lock; 562 563 ksp->ks_crtime = gethrtime(); 564 ksp->ks_snaptime = ksp->ks_crtime; 565 ksp->ks_instance = ks_instance; 566 strlcpy(ksp->ks_class, ks_class, sizeof (ksp->ks_class)); 567 ksp->ks_type = ks_type; 568 ksp->ks_flags = ks_flags; 569 ksp->ks_update = kstat_default_update; 570 ksp->ks_private = NULL; 571 ksp->ks_raw_ops.headers = NULL; 572 ksp->ks_raw_ops.data = NULL; 573 ksp->ks_raw_ops.addr = NULL; 574 ksp->ks_raw_buf = NULL; 575 ksp->ks_raw_bufsize = 0; 576 kstat_proc_entry_init(&ksp->ks_proc, ks_module, ks_name); 577 578 switch (ksp->ks_type) { 579 case KSTAT_TYPE_RAW: 580 ksp->ks_ndata = 1; 581 ksp->ks_data_size = ks_ndata; 582 break; 583 case KSTAT_TYPE_NAMED: 584 ksp->ks_ndata = ks_ndata; 585 ksp->ks_data_size = ks_ndata * sizeof (kstat_named_t); 586 break; 587 case KSTAT_TYPE_INTR: 588 ksp->ks_ndata = ks_ndata; 589 ksp->ks_data_size = ks_ndata * sizeof (kstat_intr_t); 590 break; 591 case KSTAT_TYPE_IO: 592 ksp->ks_ndata = ks_ndata; 593 ksp->ks_data_size = ks_ndata * sizeof (kstat_io_t); 594 break; 595 case KSTAT_TYPE_TIMER: 596 ksp->ks_ndata = ks_ndata; 597 ksp->ks_data_size = ks_ndata * sizeof (kstat_timer_t); 598 break; 599 default: 600 PANIC("Undefined kstat type %d\n", ksp->ks_type); 601 } 602 603 if (ksp->ks_flags & KSTAT_FLAG_VIRTUAL) { 604 ksp->ks_data = NULL; 605 } else { 606 ksp->ks_data = kmem_zalloc(ksp->ks_data_size, KM_SLEEP); 607 if (ksp->ks_data == NULL) { 608 kmem_free(ksp, sizeof (*ksp)); 609 ksp = NULL; 610 } 611 } 612 613 return (ksp); 614 } 615 EXPORT_SYMBOL(__kstat_create); 616 617 static int 618 kstat_detect_collision(kstat_proc_entry_t *kpep) 619 { 620 kstat_module_t *module; 621 kstat_proc_entry_t *tmp = NULL; 622 char *parent; 623 char *cp; 624 625 parent = kmem_asprintf("%s", kpep->kpe_module); 626 627 if ((cp = strrchr(parent, '/')) == NULL) { 628 kmem_strfree(parent); 629 return (0); 630 } 631 632 cp[0] = '\0'; 633 if ((module = kstat_find_module(parent)) != NULL) { 634 list_for_each_entry(tmp, &module->ksm_kstat_list, kpe_list) { 635 if (strncmp(tmp->kpe_name, cp+1, KSTAT_STRLEN) == 0) { 636 kmem_strfree(parent); 637 return (EEXIST); 638 } 639 } 640 } 641 642 kmem_strfree(parent); 643 return (0); 644 } 645 646 /* 647 * Add a file to the proc filesystem under the kstat namespace (i.e. 648 * /proc/spl/kstat/). The file need not necessarily be implemented as a 649 * kstat. 650 */ 651 void 652 kstat_proc_entry_install(kstat_proc_entry_t *kpep, mode_t mode, 653 const kstat_proc_op_t *proc_ops, void *data) 654 { 655 kstat_module_t *module; 656 kstat_proc_entry_t *tmp = NULL; 657 658 ASSERT(kpep); 659 660 mutex_enter(&kstat_module_lock); 661 662 module = kstat_find_module(kpep->kpe_module); 663 if (module == NULL) { 664 if (kstat_detect_collision(kpep) != 0) { 665 cmn_err(CE_WARN, "kstat_create('%s', '%s'): namespace" \ 666 " collision", kpep->kpe_module, kpep->kpe_name); 667 goto out; 668 } 669 module = kstat_create_module(kpep->kpe_module); 670 if (module == NULL) 671 goto out; 672 } 673 674 /* 675 * We can only have one entry of this name per module. If one already 676 * exists, replace it by first removing the proc entry, then removing 677 * it from the list. The kstat itself lives on; it just can't be 678 * inspected through the filesystem. 679 */ 680 list_for_each_entry(tmp, &module->ksm_kstat_list, kpe_list) { 681 if (tmp->kpe_proc != NULL && 682 strncmp(tmp->kpe_name, kpep->kpe_name, KSTAT_STRLEN) == 0) { 683 ASSERT3P(tmp->kpe_owner, ==, module); 684 remove_proc_entry(tmp->kpe_name, module->ksm_proc); 685 tmp->kpe_proc = NULL; 686 list_del_init(&tmp->kpe_list); 687 break; 688 } 689 } 690 691 list_add_tail(&kpep->kpe_list, &module->ksm_kstat_list); 692 693 kpep->kpe_owner = module; 694 kpep->kpe_proc = proc_create_data(kpep->kpe_name, mode, 695 module->ksm_proc, proc_ops, data); 696 if (kpep->kpe_proc == NULL) { 697 list_del_init(&kpep->kpe_list); 698 if (list_empty(&module->ksm_kstat_list)) 699 kstat_delete_module(module); 700 } 701 out: 702 mutex_exit(&kstat_module_lock); 703 704 } 705 EXPORT_SYMBOL(kstat_proc_entry_install); 706 707 void 708 __kstat_install(kstat_t *ksp) 709 { 710 ASSERT(ksp); 711 mode_t mode; 712 /* Specify permission modes for different kstats */ 713 if (strncmp(ksp->ks_proc.kpe_name, "dbufs", KSTAT_STRLEN) == 0) { 714 mode = 0600; 715 } else { 716 mode = 0644; 717 } 718 kstat_proc_entry_install( 719 &ksp->ks_proc, mode, &proc_kstat_operations, ksp); 720 } 721 EXPORT_SYMBOL(__kstat_install); 722 723 void 724 kstat_proc_entry_delete(kstat_proc_entry_t *kpep) 725 { 726 kstat_module_t *module = kpep->kpe_owner; 727 if (kpep->kpe_proc) 728 remove_proc_entry(kpep->kpe_name, module->ksm_proc); 729 730 mutex_enter(&kstat_module_lock); 731 list_del_init(&kpep->kpe_list); 732 733 /* 734 * Remove top level module directory if it wasn't empty before, but now 735 * is. 736 */ 737 if (kpep->kpe_proc && list_empty(&module->ksm_kstat_list)) 738 kstat_delete_module(module); 739 mutex_exit(&kstat_module_lock); 740 741 } 742 EXPORT_SYMBOL(kstat_proc_entry_delete); 743 744 void 745 __kstat_delete(kstat_t *ksp) 746 { 747 kstat_proc_entry_delete(&ksp->ks_proc); 748 749 if (!(ksp->ks_flags & KSTAT_FLAG_VIRTUAL)) 750 kmem_free(ksp->ks_data, ksp->ks_data_size); 751 752 ksp->ks_lock = NULL; 753 mutex_destroy(&ksp->ks_private_lock); 754 kmem_free(ksp, sizeof (*ksp)); 755 } 756 EXPORT_SYMBOL(__kstat_delete); 757 758 int 759 spl_kstat_init(void) 760 { 761 mutex_init(&kstat_module_lock, NULL, MUTEX_DEFAULT, NULL); 762 INIT_LIST_HEAD(&kstat_module_list); 763 kstat_id = 0; 764 return (0); 765 } 766 767 void 768 spl_kstat_fini(void) 769 { 770 ASSERT(list_empty(&kstat_module_list)); 771 mutex_destroy(&kstat_module_lock); 772 } 773