1 /* 2 * Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC. 3 * Copyright (C) 2007 The Regents of the University of California. 4 * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER). 5 * Written by Brian Behlendorf <behlendorf1@llnl.gov>. 6 * UCRL-CODE-235197 7 * 8 * This file is part of the SPL, Solaris Porting Layer. 9 * 10 * The SPL is free software; you can redistribute it and/or modify it 11 * under the terms of the GNU General Public License as published by the 12 * Free Software Foundation; either version 2 of the License, or (at your 13 * option) any later version. 14 * 15 * The SPL is distributed in the hope that it will be useful, but WITHOUT 16 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 17 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 18 * for more details. 19 * 20 * You should have received a copy of the GNU General Public License along 21 * with the SPL. If not, see <http://www.gnu.org/licenses/>. 22 * 23 * Solaris Porting Layer (SPL) Proc Implementation. 24 */ 25 26 #include <sys/systeminfo.h> 27 #include <sys/kstat.h> 28 #include <sys/kmem.h> 29 #include <sys/kmem_cache.h> 30 #include <sys/vmem.h> 31 #include <sys/taskq.h> 32 #include <sys/proc.h> 33 #include <linux/ctype.h> 34 #include <linux/kmod.h> 35 #include <linux/seq_file.h> 36 #include <linux/uaccess.h> 37 #include <linux/version.h> 38 39 #if defined(CONSTIFY_PLUGIN) && LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0) 40 typedef struct ctl_table __no_const spl_ctl_table; 41 #else 42 typedef struct ctl_table spl_ctl_table; 43 #endif 44 45 static unsigned long table_min = 0; 46 static unsigned long table_max = ~0; 47 48 static struct ctl_table_header *spl_header = NULL; 49 static struct proc_dir_entry *proc_spl = NULL; 50 static struct proc_dir_entry *proc_spl_kmem = NULL; 51 static struct proc_dir_entry *proc_spl_kmem_slab = NULL; 52 static struct proc_dir_entry *proc_spl_taskq_all = NULL; 53 static struct proc_dir_entry *proc_spl_taskq = NULL; 54 struct proc_dir_entry *proc_spl_kstat = NULL; 55 56 static int 57 proc_copyin_string(char *kbuffer, int kbuffer_size, const char *ubuffer, 58 int ubuffer_size) 59 { 60 int size; 61 62 if (ubuffer_size > kbuffer_size) 63 return (-EOVERFLOW); 64 65 if (copy_from_user((void *)kbuffer, (void *)ubuffer, ubuffer_size)) 66 return (-EFAULT); 67 68 /* strip trailing whitespace */ 69 size = strnlen(kbuffer, ubuffer_size); 70 while (size-- >= 0) 71 if (!isspace(kbuffer[size])) 72 break; 73 74 /* empty string */ 75 if (size < 0) 76 return (-EINVAL); 77 78 /* no space to terminate */ 79 if (size == kbuffer_size) 80 return (-EOVERFLOW); 81 82 kbuffer[size + 1] = 0; 83 return (0); 84 } 85 86 static int 87 proc_copyout_string(char *ubuffer, int ubuffer_size, const char *kbuffer, 88 char *append) 89 { 90 /* 91 * NB if 'append' != NULL, it's a single character to append to the 92 * copied out string - usually "\n", for /proc entries and 93 * (i.e. a terminating zero byte) for sysctl entries 94 */ 95 int size = MIN(strlen(kbuffer), ubuffer_size); 96 97 if (copy_to_user(ubuffer, kbuffer, size)) 98 return (-EFAULT); 99 100 if (append != NULL && size < ubuffer_size) { 101 if (copy_to_user(ubuffer + size, append, 1)) 102 return (-EFAULT); 103 104 size++; 105 } 106 107 return (size); 108 } 109 110 #ifdef DEBUG_KMEM 111 static int 112 proc_domemused(struct ctl_table *table, int write, 113 void __user *buffer, size_t *lenp, loff_t *ppos) 114 { 115 int rc = 0; 116 unsigned long min = 0, max = ~0, val; 117 spl_ctl_table dummy = *table; 118 119 dummy.data = &val; 120 dummy.proc_handler = &proc_dointvec; 121 dummy.extra1 = &min; 122 dummy.extra2 = &max; 123 124 if (write) { 125 *ppos += *lenp; 126 } else { 127 #ifdef HAVE_ATOMIC64_T 128 val = atomic64_read((atomic64_t *)table->data); 129 #else 130 val = atomic_read((atomic_t *)table->data); 131 #endif /* HAVE_ATOMIC64_T */ 132 rc = proc_doulongvec_minmax(&dummy, write, buffer, lenp, ppos); 133 } 134 135 return (rc); 136 } 137 #endif /* DEBUG_KMEM */ 138 139 static int 140 proc_doslab(struct ctl_table *table, int write, 141 void __user *buffer, size_t *lenp, loff_t *ppos) 142 { 143 int rc = 0; 144 unsigned long min = 0, max = ~0, val = 0, mask; 145 spl_ctl_table dummy = *table; 146 spl_kmem_cache_t *skc = NULL; 147 148 dummy.data = &val; 149 dummy.proc_handler = &proc_dointvec; 150 dummy.extra1 = &min; 151 dummy.extra2 = &max; 152 153 if (write) { 154 *ppos += *lenp; 155 } else { 156 down_read(&spl_kmem_cache_sem); 157 mask = (unsigned long)table->data; 158 159 list_for_each_entry(skc, &spl_kmem_cache_list, skc_list) { 160 161 /* Only use slabs of the correct kmem/vmem type */ 162 if (!(skc->skc_flags & mask)) 163 continue; 164 165 /* Sum the specified field for selected slabs */ 166 switch (mask & (KMC_TOTAL | KMC_ALLOC | KMC_MAX)) { 167 case KMC_TOTAL: 168 val += skc->skc_slab_size * skc->skc_slab_total; 169 break; 170 case KMC_ALLOC: 171 val += skc->skc_obj_size * skc->skc_obj_alloc; 172 break; 173 case KMC_MAX: 174 val += skc->skc_obj_size * skc->skc_obj_max; 175 break; 176 } 177 } 178 179 up_read(&spl_kmem_cache_sem); 180 rc = proc_doulongvec_minmax(&dummy, write, buffer, lenp, ppos); 181 } 182 183 return (rc); 184 } 185 186 static int 187 proc_dohostid(struct ctl_table *table, int write, 188 void __user *buffer, size_t *lenp, loff_t *ppos) 189 { 190 int len, rc = 0; 191 char *end, str[32]; 192 193 if (write) { 194 /* 195 * We can't use proc_doulongvec_minmax() in the write 196 * case here because hostid while a hex value has no 197 * leading 0x which confuses the helper function. 198 */ 199 rc = proc_copyin_string(str, sizeof (str), buffer, *lenp); 200 if (rc < 0) 201 return (rc); 202 203 spl_hostid = simple_strtoul(str, &end, 16); 204 if (str == end) 205 return (-EINVAL); 206 207 } else { 208 len = snprintf(str, sizeof (str), "%lx", 209 (unsigned long) zone_get_hostid(NULL)); 210 if (*ppos >= len) 211 rc = 0; 212 else 213 rc = proc_copyout_string(buffer, 214 *lenp, str + *ppos, "\n"); 215 216 if (rc >= 0) { 217 *lenp = rc; 218 *ppos += rc; 219 } 220 } 221 222 return (rc); 223 } 224 225 static void 226 taskq_seq_show_headers(struct seq_file *f) 227 { 228 seq_printf(f, "%-25s %5s %5s %5s %5s %5s %5s %12s %5s %10s\n", 229 "taskq", "act", "nthr", "spwn", "maxt", "pri", 230 "mina", "maxa", "cura", "flags"); 231 } 232 233 /* indices into the lheads array below */ 234 #define LHEAD_PEND 0 235 #define LHEAD_PRIO 1 236 #define LHEAD_DELAY 2 237 #define LHEAD_WAIT 3 238 #define LHEAD_ACTIVE 4 239 #define LHEAD_SIZE 5 240 241 /* BEGIN CSTYLED */ 242 static unsigned int spl_max_show_tasks = 512; 243 module_param(spl_max_show_tasks, uint, 0644); 244 MODULE_PARM_DESC(spl_max_show_tasks, "Max number of tasks shown in taskq proc"); 245 /* END CSTYLED */ 246 247 static int 248 taskq_seq_show_impl(struct seq_file *f, void *p, boolean_t allflag) 249 { 250 taskq_t *tq = p; 251 taskq_thread_t *tqt = NULL; 252 spl_wait_queue_entry_t *wq; 253 struct task_struct *tsk; 254 taskq_ent_t *tqe; 255 char name[100]; 256 struct list_head *lheads[LHEAD_SIZE], *lh; 257 static char *list_names[LHEAD_SIZE] = 258 {"pend", "prio", "delay", "wait", "active" }; 259 int i, j, have_lheads = 0; 260 unsigned long wflags, flags; 261 262 spin_lock_irqsave_nested(&tq->tq_lock, flags, tq->tq_lock_class); 263 spin_lock_irqsave(&tq->tq_wait_waitq.lock, wflags); 264 265 /* get the various lists and check whether they're empty */ 266 lheads[LHEAD_PEND] = &tq->tq_pend_list; 267 lheads[LHEAD_PRIO] = &tq->tq_prio_list; 268 lheads[LHEAD_DELAY] = &tq->tq_delay_list; 269 #ifdef HAVE_WAIT_QUEUE_HEAD_ENTRY 270 lheads[LHEAD_WAIT] = &tq->tq_wait_waitq.head; 271 #else 272 lheads[LHEAD_WAIT] = &tq->tq_wait_waitq.task_list; 273 #endif 274 lheads[LHEAD_ACTIVE] = &tq->tq_active_list; 275 276 for (i = 0; i < LHEAD_SIZE; ++i) { 277 if (list_empty(lheads[i])) 278 lheads[i] = NULL; 279 else 280 ++have_lheads; 281 } 282 283 /* early return in non-"all" mode if lists are all empty */ 284 if (!allflag && !have_lheads) { 285 spin_unlock_irqrestore(&tq->tq_wait_waitq.lock, wflags); 286 spin_unlock_irqrestore(&tq->tq_lock, flags); 287 return (0); 288 } 289 290 /* unlock the waitq quickly */ 291 if (!lheads[LHEAD_WAIT]) 292 spin_unlock_irqrestore(&tq->tq_wait_waitq.lock, wflags); 293 294 /* show the base taskq contents */ 295 snprintf(name, sizeof (name), "%s/%d", tq->tq_name, tq->tq_instance); 296 seq_printf(f, "%-25s ", name); 297 seq_printf(f, "%5d %5d %5d %5d %5d %5d %12d %5d %10x\n", 298 tq->tq_nactive, tq->tq_nthreads, tq->tq_nspawn, 299 tq->tq_maxthreads, tq->tq_pri, tq->tq_minalloc, tq->tq_maxalloc, 300 tq->tq_nalloc, tq->tq_flags); 301 302 /* show the active list */ 303 if (lheads[LHEAD_ACTIVE]) { 304 j = 0; 305 list_for_each_entry(tqt, &tq->tq_active_list, tqt_active_list) { 306 if (j == 0) 307 seq_printf(f, "\t%s:", 308 list_names[LHEAD_ACTIVE]); 309 else if (j == 2) { 310 seq_printf(f, "\n\t "); 311 j = 0; 312 } 313 seq_printf(f, " [%d]%pf(%ps)", 314 tqt->tqt_thread->pid, 315 tqt->tqt_task->tqent_func, 316 tqt->tqt_task->tqent_arg); 317 ++j; 318 } 319 seq_printf(f, "\n"); 320 } 321 322 for (i = LHEAD_PEND; i <= LHEAD_WAIT; ++i) 323 if (lheads[i]) { 324 j = 0; 325 list_for_each(lh, lheads[i]) { 326 if (spl_max_show_tasks != 0 && 327 j >= spl_max_show_tasks) { 328 seq_printf(f, "\n\t(truncated)"); 329 break; 330 } 331 /* show the wait waitq list */ 332 if (i == LHEAD_WAIT) { 333 #ifdef HAVE_WAIT_QUEUE_HEAD_ENTRY 334 wq = list_entry(lh, 335 spl_wait_queue_entry_t, entry); 336 #else 337 wq = list_entry(lh, 338 spl_wait_queue_entry_t, task_list); 339 #endif 340 if (j == 0) 341 seq_printf(f, "\t%s:", 342 list_names[i]); 343 else if (j % 8 == 0) 344 seq_printf(f, "\n\t "); 345 346 tsk = wq->private; 347 seq_printf(f, " %d", tsk->pid); 348 /* pend, prio and delay lists */ 349 } else { 350 tqe = list_entry(lh, taskq_ent_t, 351 tqent_list); 352 if (j == 0) 353 seq_printf(f, "\t%s:", 354 list_names[i]); 355 else if (j % 2 == 0) 356 seq_printf(f, "\n\t "); 357 358 seq_printf(f, " %pf(%ps)", 359 tqe->tqent_func, 360 tqe->tqent_arg); 361 } 362 ++j; 363 } 364 seq_printf(f, "\n"); 365 } 366 if (lheads[LHEAD_WAIT]) 367 spin_unlock_irqrestore(&tq->tq_wait_waitq.lock, wflags); 368 spin_unlock_irqrestore(&tq->tq_lock, flags); 369 370 return (0); 371 } 372 373 static int 374 taskq_all_seq_show(struct seq_file *f, void *p) 375 { 376 return (taskq_seq_show_impl(f, p, B_TRUE)); 377 } 378 379 static int 380 taskq_seq_show(struct seq_file *f, void *p) 381 { 382 return (taskq_seq_show_impl(f, p, B_FALSE)); 383 } 384 385 static void * 386 taskq_seq_start(struct seq_file *f, loff_t *pos) 387 { 388 struct list_head *p; 389 loff_t n = *pos; 390 391 down_read(&tq_list_sem); 392 if (!n) 393 taskq_seq_show_headers(f); 394 395 p = tq_list.next; 396 while (n--) { 397 p = p->next; 398 if (p == &tq_list) 399 return (NULL); 400 } 401 402 return (list_entry(p, taskq_t, tq_taskqs)); 403 } 404 405 static void * 406 taskq_seq_next(struct seq_file *f, void *p, loff_t *pos) 407 { 408 taskq_t *tq = p; 409 410 ++*pos; 411 return ((tq->tq_taskqs.next == &tq_list) ? 412 NULL : list_entry(tq->tq_taskqs.next, taskq_t, tq_taskqs)); 413 } 414 415 static void 416 slab_seq_show_headers(struct seq_file *f) 417 { 418 seq_printf(f, 419 "--------------------- cache ----------" 420 "--------------------------------------------- " 421 "----- slab ------ " 422 "---- object ----- " 423 "--- emergency ---\n"); 424 seq_printf(f, 425 "name " 426 " flags size alloc slabsize objsize " 427 "total alloc max " 428 "total alloc max " 429 "dlock alloc max\n"); 430 } 431 432 static int 433 slab_seq_show(struct seq_file *f, void *p) 434 { 435 spl_kmem_cache_t *skc = p; 436 437 ASSERT(skc->skc_magic == SKC_MAGIC); 438 439 if (skc->skc_flags & KMC_SLAB) { 440 /* 441 * This cache is backed by a generic Linux kmem cache which 442 * has its own accounting. For these caches we only track 443 * the number of active allocated objects that exist within 444 * the underlying Linux slabs. For the overall statistics of 445 * the underlying Linux cache please refer to /proc/slabinfo. 446 */ 447 spin_lock(&skc->skc_lock); 448 uint64_t objs_allocated = 449 percpu_counter_sum(&skc->skc_linux_alloc); 450 seq_printf(f, "%-36s ", skc->skc_name); 451 seq_printf(f, "0x%05lx %9s %9lu %8s %8u " 452 "%5s %5s %5s %5s %5lu %5s %5s %5s %5s\n", 453 (long unsigned)skc->skc_flags, 454 "-", 455 (long unsigned)(skc->skc_obj_size * objs_allocated), 456 "-", 457 (unsigned)skc->skc_obj_size, 458 "-", "-", "-", "-", 459 (long unsigned)objs_allocated, 460 "-", "-", "-", "-"); 461 spin_unlock(&skc->skc_lock); 462 return (0); 463 } 464 465 spin_lock(&skc->skc_lock); 466 seq_printf(f, "%-36s ", skc->skc_name); 467 seq_printf(f, "0x%05lx %9lu %9lu %8u %8u " 468 "%5lu %5lu %5lu %5lu %5lu %5lu %5lu %5lu %5lu\n", 469 (long unsigned)skc->skc_flags, 470 (long unsigned)(skc->skc_slab_size * skc->skc_slab_total), 471 (long unsigned)(skc->skc_obj_size * skc->skc_obj_alloc), 472 (unsigned)skc->skc_slab_size, 473 (unsigned)skc->skc_obj_size, 474 (long unsigned)skc->skc_slab_total, 475 (long unsigned)skc->skc_slab_alloc, 476 (long unsigned)skc->skc_slab_max, 477 (long unsigned)skc->skc_obj_total, 478 (long unsigned)skc->skc_obj_alloc, 479 (long unsigned)skc->skc_obj_max, 480 (long unsigned)skc->skc_obj_deadlock, 481 (long unsigned)skc->skc_obj_emergency, 482 (long unsigned)skc->skc_obj_emergency_max); 483 spin_unlock(&skc->skc_lock); 484 return (0); 485 } 486 487 static void * 488 slab_seq_start(struct seq_file *f, loff_t *pos) 489 { 490 struct list_head *p; 491 loff_t n = *pos; 492 493 down_read(&spl_kmem_cache_sem); 494 if (!n) 495 slab_seq_show_headers(f); 496 497 p = spl_kmem_cache_list.next; 498 while (n--) { 499 p = p->next; 500 if (p == &spl_kmem_cache_list) 501 return (NULL); 502 } 503 504 return (list_entry(p, spl_kmem_cache_t, skc_list)); 505 } 506 507 static void * 508 slab_seq_next(struct seq_file *f, void *p, loff_t *pos) 509 { 510 spl_kmem_cache_t *skc = p; 511 512 ++*pos; 513 return ((skc->skc_list.next == &spl_kmem_cache_list) ? 514 NULL : list_entry(skc->skc_list.next, spl_kmem_cache_t, skc_list)); 515 } 516 517 static void 518 slab_seq_stop(struct seq_file *f, void *v) 519 { 520 up_read(&spl_kmem_cache_sem); 521 } 522 523 static struct seq_operations slab_seq_ops = { 524 .show = slab_seq_show, 525 .start = slab_seq_start, 526 .next = slab_seq_next, 527 .stop = slab_seq_stop, 528 }; 529 530 static int 531 proc_slab_open(struct inode *inode, struct file *filp) 532 { 533 return (seq_open(filp, &slab_seq_ops)); 534 } 535 536 static const kstat_proc_op_t proc_slab_operations = { 537 #ifdef HAVE_PROC_OPS_STRUCT 538 .proc_open = proc_slab_open, 539 .proc_read = seq_read, 540 .proc_lseek = seq_lseek, 541 .proc_release = seq_release, 542 #else 543 .open = proc_slab_open, 544 .read = seq_read, 545 .llseek = seq_lseek, 546 .release = seq_release, 547 #endif 548 }; 549 550 static void 551 taskq_seq_stop(struct seq_file *f, void *v) 552 { 553 up_read(&tq_list_sem); 554 } 555 556 static struct seq_operations taskq_all_seq_ops = { 557 .show = taskq_all_seq_show, 558 .start = taskq_seq_start, 559 .next = taskq_seq_next, 560 .stop = taskq_seq_stop, 561 }; 562 563 static struct seq_operations taskq_seq_ops = { 564 .show = taskq_seq_show, 565 .start = taskq_seq_start, 566 .next = taskq_seq_next, 567 .stop = taskq_seq_stop, 568 }; 569 570 static int 571 proc_taskq_all_open(struct inode *inode, struct file *filp) 572 { 573 return (seq_open(filp, &taskq_all_seq_ops)); 574 } 575 576 static int 577 proc_taskq_open(struct inode *inode, struct file *filp) 578 { 579 return (seq_open(filp, &taskq_seq_ops)); 580 } 581 582 static const kstat_proc_op_t proc_taskq_all_operations = { 583 #ifdef HAVE_PROC_OPS_STRUCT 584 .proc_open = proc_taskq_all_open, 585 .proc_read = seq_read, 586 .proc_lseek = seq_lseek, 587 .proc_release = seq_release, 588 #else 589 .open = proc_taskq_all_open, 590 .read = seq_read, 591 .llseek = seq_lseek, 592 .release = seq_release, 593 #endif 594 }; 595 596 static const kstat_proc_op_t proc_taskq_operations = { 597 #ifdef HAVE_PROC_OPS_STRUCT 598 .proc_open = proc_taskq_open, 599 .proc_read = seq_read, 600 .proc_lseek = seq_lseek, 601 .proc_release = seq_release, 602 #else 603 .open = proc_taskq_open, 604 .read = seq_read, 605 .llseek = seq_lseek, 606 .release = seq_release, 607 #endif 608 }; 609 610 static struct ctl_table spl_kmem_table[] = { 611 #ifdef DEBUG_KMEM 612 { 613 .procname = "kmem_used", 614 .data = &kmem_alloc_used, 615 #ifdef HAVE_ATOMIC64_T 616 .maxlen = sizeof (atomic64_t), 617 #else 618 .maxlen = sizeof (atomic_t), 619 #endif /* HAVE_ATOMIC64_T */ 620 .mode = 0444, 621 .proc_handler = &proc_domemused, 622 }, 623 { 624 .procname = "kmem_max", 625 .data = &kmem_alloc_max, 626 .maxlen = sizeof (unsigned long), 627 .extra1 = &table_min, 628 .extra2 = &table_max, 629 .mode = 0444, 630 .proc_handler = &proc_doulongvec_minmax, 631 }, 632 #endif /* DEBUG_KMEM */ 633 { 634 .procname = "slab_kvmem_total", 635 .data = (void *)(KMC_KVMEM | KMC_TOTAL), 636 .maxlen = sizeof (unsigned long), 637 .extra1 = &table_min, 638 .extra2 = &table_max, 639 .mode = 0444, 640 .proc_handler = &proc_doslab, 641 }, 642 { 643 .procname = "slab_kvmem_alloc", 644 .data = (void *)(KMC_KVMEM | KMC_ALLOC), 645 .maxlen = sizeof (unsigned long), 646 .extra1 = &table_min, 647 .extra2 = &table_max, 648 .mode = 0444, 649 .proc_handler = &proc_doslab, 650 }, 651 { 652 .procname = "slab_kvmem_max", 653 .data = (void *)(KMC_KVMEM | KMC_MAX), 654 .maxlen = sizeof (unsigned long), 655 .extra1 = &table_min, 656 .extra2 = &table_max, 657 .mode = 0444, 658 .proc_handler = &proc_doslab, 659 }, 660 {}, 661 }; 662 663 static struct ctl_table spl_kstat_table[] = { 664 {}, 665 }; 666 667 static struct ctl_table spl_table[] = { 668 /* 669 * NB No .strategy entries have been provided since 670 * sysctl(8) prefers to go via /proc for portability. 671 */ 672 { 673 .procname = "gitrev", 674 .data = spl_gitrev, 675 .maxlen = sizeof (spl_gitrev), 676 .mode = 0444, 677 .proc_handler = &proc_dostring, 678 }, 679 { 680 .procname = "hostid", 681 .data = &spl_hostid, 682 .maxlen = sizeof (unsigned long), 683 .mode = 0644, 684 .proc_handler = &proc_dohostid, 685 }, 686 { 687 .procname = "kmem", 688 .mode = 0555, 689 .child = spl_kmem_table, 690 }, 691 { 692 .procname = "kstat", 693 .mode = 0555, 694 .child = spl_kstat_table, 695 }, 696 {}, 697 }; 698 699 static struct ctl_table spl_dir[] = { 700 { 701 .procname = "spl", 702 .mode = 0555, 703 .child = spl_table, 704 }, 705 {} 706 }; 707 708 static struct ctl_table spl_root[] = { 709 { 710 .procname = "kernel", 711 .mode = 0555, 712 .child = spl_dir, 713 }, 714 {} 715 }; 716 717 int 718 spl_proc_init(void) 719 { 720 int rc = 0; 721 722 spl_header = register_sysctl_table(spl_root); 723 if (spl_header == NULL) 724 return (-EUNATCH); 725 726 proc_spl = proc_mkdir("spl", NULL); 727 if (proc_spl == NULL) { 728 rc = -EUNATCH; 729 goto out; 730 } 731 732 proc_spl_taskq_all = proc_create_data("taskq-all", 0444, proc_spl, 733 &proc_taskq_all_operations, NULL); 734 if (proc_spl_taskq_all == NULL) { 735 rc = -EUNATCH; 736 goto out; 737 } 738 739 proc_spl_taskq = proc_create_data("taskq", 0444, proc_spl, 740 &proc_taskq_operations, NULL); 741 if (proc_spl_taskq == NULL) { 742 rc = -EUNATCH; 743 goto out; 744 } 745 746 proc_spl_kmem = proc_mkdir("kmem", proc_spl); 747 if (proc_spl_kmem == NULL) { 748 rc = -EUNATCH; 749 goto out; 750 } 751 752 proc_spl_kmem_slab = proc_create_data("slab", 0444, proc_spl_kmem, 753 &proc_slab_operations, NULL); 754 if (proc_spl_kmem_slab == NULL) { 755 rc = -EUNATCH; 756 goto out; 757 } 758 759 proc_spl_kstat = proc_mkdir("kstat", proc_spl); 760 if (proc_spl_kstat == NULL) { 761 rc = -EUNATCH; 762 goto out; 763 } 764 out: 765 if (rc) { 766 remove_proc_entry("kstat", proc_spl); 767 remove_proc_entry("slab", proc_spl_kmem); 768 remove_proc_entry("kmem", proc_spl); 769 remove_proc_entry("taskq-all", proc_spl); 770 remove_proc_entry("taskq", proc_spl); 771 remove_proc_entry("spl", NULL); 772 unregister_sysctl_table(spl_header); 773 } 774 775 return (rc); 776 } 777 778 void 779 spl_proc_fini(void) 780 { 781 remove_proc_entry("kstat", proc_spl); 782 remove_proc_entry("slab", proc_spl_kmem); 783 remove_proc_entry("kmem", proc_spl); 784 remove_proc_entry("taskq-all", proc_spl); 785 remove_proc_entry("taskq", proc_spl); 786 remove_proc_entry("spl", NULL); 787 788 ASSERT(spl_header != NULL); 789 unregister_sysctl_table(spl_header); 790 } 791