]> git.proxmox.com Git - mirror_spl.git/blob - module/spl/spl-proc.c
Remove kallsyms_lookup_name() wrapper
[mirror_spl.git] / module / spl / spl-proc.c
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 * For details, see <http://zfsonlinux.org/>.
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) Proc Implementation.
25 \*****************************************************************************/
26
27 #include <sys/systeminfo.h>
28 #include <sys/kstat.h>
29 #include <linux/kmod.h>
30 #include <linux/seq_file.h>
31 #include <linux/proc_compat.h>
32 #include <linux/version.h>
33 #include <spl-debug.h>
34
35 #ifdef SS_DEBUG_SUBSYS
36 #undef SS_DEBUG_SUBSYS
37 #endif
38
39 #define SS_DEBUG_SUBSYS SS_PROC
40
41 #if defined(CONSTIFY_PLUGIN) && LINUX_VERSION_CODE >= KERNEL_VERSION(3,8,0)
42 typedef struct ctl_table __no_const spl_ctl_table;
43 #else
44 typedef struct ctl_table spl_ctl_table;
45 #endif
46
47 #ifdef DEBUG_KMEM
48 static unsigned long table_min = 0;
49 static unsigned long table_max = ~0;
50 #endif
51
52 static struct ctl_table_header *spl_header = NULL;
53 static struct proc_dir_entry *proc_spl = NULL;
54 #ifdef DEBUG_KMEM
55 static struct proc_dir_entry *proc_spl_kmem = NULL;
56 static struct proc_dir_entry *proc_spl_kmem_slab = NULL;
57 #endif /* DEBUG_KMEM */
58 struct proc_dir_entry *proc_spl_kstat = NULL;
59
60 static int
61 proc_copyin_string(char *kbuffer, int kbuffer_size,
62 const char *ubuffer, int ubuffer_size)
63 {
64 int size;
65
66 if (ubuffer_size > kbuffer_size)
67 return -EOVERFLOW;
68
69 if (copy_from_user((void *)kbuffer, (void *)ubuffer, ubuffer_size))
70 return -EFAULT;
71
72 /* strip trailing whitespace */
73 size = strnlen(kbuffer, ubuffer_size);
74 while (size-- >= 0)
75 if (!isspace(kbuffer[size]))
76 break;
77
78 /* empty string */
79 if (size < 0)
80 return -EINVAL;
81
82 /* no space to terminate */
83 if (size == kbuffer_size)
84 return -EOVERFLOW;
85
86 kbuffer[size + 1] = 0;
87 return 0;
88 }
89
90 static int
91 proc_copyout_string(char *ubuffer, int ubuffer_size,
92 const char *kbuffer, char *append)
93 {
94 /* NB if 'append' != NULL, it's a single character to append to the
95 * copied out string - usually "\n", for /proc entries and
96 * (i.e. a terminating zero byte) for sysctl entries
97 */
98 int size = MIN(strlen(kbuffer), ubuffer_size);
99
100 if (copy_to_user(ubuffer, kbuffer, size))
101 return -EFAULT;
102
103 if (append != NULL && size < ubuffer_size) {
104 if (copy_to_user(ubuffer + size, append, 1))
105 return -EFAULT;
106
107 size++;
108 }
109
110 return size;
111 }
112
113 #ifdef DEBUG_LOG
114 SPL_PROC_HANDLER(proc_dobitmasks)
115 {
116 unsigned long *mask = table->data;
117 int is_subsys = (mask == &spl_debug_subsys) ? 1 : 0;
118 int is_printk = (mask == &spl_debug_printk) ? 1 : 0;
119 int size = 512, rc;
120 char *str;
121 SENTRY;
122
123 str = kmem_alloc(size, KM_SLEEP);
124 if (str == NULL)
125 SRETURN(-ENOMEM);
126
127 if (write) {
128 rc = proc_copyin_string(str, size, buffer, *lenp);
129 if (rc < 0)
130 SRETURN(rc);
131
132 rc = spl_debug_str2mask(mask, str, is_subsys);
133 /* Always print BUG/ASSERT to console, so keep this mask */
134 if (is_printk)
135 *mask |= SD_EMERG;
136
137 *ppos += *lenp;
138 } else {
139 rc = spl_debug_mask2str(str, size, *mask, is_subsys);
140 if (*ppos >= rc)
141 rc = 0;
142 else
143 rc = proc_copyout_string(buffer, *lenp,
144 str + *ppos, "\n");
145 if (rc >= 0) {
146 *lenp = rc;
147 *ppos += rc;
148 }
149 }
150
151 kmem_free(str, size);
152 SRETURN(rc);
153 }
154
155 SPL_PROC_HANDLER(proc_debug_mb)
156 {
157 char str[32];
158 int rc, len;
159 SENTRY;
160
161 if (write) {
162 rc = proc_copyin_string(str, sizeof(str), buffer, *lenp);
163 if (rc < 0)
164 SRETURN(rc);
165
166 rc = spl_debug_set_mb(simple_strtoul(str, NULL, 0));
167 *ppos += *lenp;
168 } else {
169 len = snprintf(str, sizeof(str), "%d", spl_debug_get_mb());
170 if (*ppos >= len)
171 rc = 0;
172 else
173 rc = proc_copyout_string(buffer,*lenp,str+*ppos,"\n");
174
175 if (rc >= 0) {
176 *lenp = rc;
177 *ppos += rc;
178 }
179 }
180
181 SRETURN(rc);
182 }
183
184 SPL_PROC_HANDLER(proc_dump_kernel)
185 {
186 SENTRY;
187
188 if (write) {
189 spl_debug_dumplog(0);
190 *ppos += *lenp;
191 } else {
192 *lenp = 0;
193 }
194
195 SRETURN(0);
196 }
197
198 SPL_PROC_HANDLER(proc_force_bug)
199 {
200 SENTRY;
201
202 if (write)
203 PANIC("Crashing due to forced panic\n");
204 else
205 *lenp = 0;
206
207 SRETURN(0);
208 }
209
210 SPL_PROC_HANDLER(proc_console_max_delay_cs)
211 {
212 int rc, max_delay_cs;
213 spl_ctl_table dummy = *table;
214 long d;
215 SENTRY;
216
217 dummy.data = &max_delay_cs;
218 dummy.proc_handler = &proc_dointvec;
219
220 if (write) {
221 max_delay_cs = 0;
222 rc = spl_proc_dointvec(&dummy,write,filp,buffer,lenp,ppos);
223 if (rc < 0)
224 SRETURN(rc);
225
226 if (max_delay_cs <= 0)
227 SRETURN(-EINVAL);
228
229 d = (max_delay_cs * HZ) / 100;
230 if (d == 0 || d < spl_console_min_delay)
231 SRETURN(-EINVAL);
232
233 spl_console_max_delay = d;
234 } else {
235 max_delay_cs = (spl_console_max_delay * 100) / HZ;
236 rc = spl_proc_dointvec(&dummy,write,filp,buffer,lenp,ppos);
237 }
238
239 SRETURN(rc);
240 }
241
242 SPL_PROC_HANDLER(proc_console_min_delay_cs)
243 {
244 int rc, min_delay_cs;
245 spl_ctl_table dummy = *table;
246 long d;
247 SENTRY;
248
249 dummy.data = &min_delay_cs;
250 dummy.proc_handler = &proc_dointvec;
251
252 if (write) {
253 min_delay_cs = 0;
254 rc = spl_proc_dointvec(&dummy,write,filp,buffer,lenp,ppos);
255 if (rc < 0)
256 SRETURN(rc);
257
258 if (min_delay_cs <= 0)
259 SRETURN(-EINVAL);
260
261 d = (min_delay_cs * HZ) / 100;
262 if (d == 0 || d > spl_console_max_delay)
263 SRETURN(-EINVAL);
264
265 spl_console_min_delay = d;
266 } else {
267 min_delay_cs = (spl_console_min_delay * 100) / HZ;
268 rc = spl_proc_dointvec(&dummy,write,filp,buffer,lenp,ppos);
269 }
270
271 SRETURN(rc);
272 }
273
274 SPL_PROC_HANDLER(proc_console_backoff)
275 {
276 int rc, backoff;
277 spl_ctl_table dummy = *table;
278 SENTRY;
279
280 dummy.data = &backoff;
281 dummy.proc_handler = &proc_dointvec;
282
283 if (write) {
284 backoff = 0;
285 rc = spl_proc_dointvec(&dummy,write,filp,buffer,lenp,ppos);
286 if (rc < 0)
287 SRETURN(rc);
288
289 if (backoff <= 0)
290 SRETURN(-EINVAL);
291
292 spl_console_backoff = backoff;
293 } else {
294 backoff = spl_console_backoff;
295 rc = spl_proc_dointvec(&dummy,write,filp,buffer,lenp,ppos);
296 }
297
298 SRETURN(rc);
299 }
300 #endif /* DEBUG_LOG */
301
302 #ifdef DEBUG_KMEM
303 SPL_PROC_HANDLER(proc_domemused)
304 {
305 int rc = 0;
306 unsigned long min = 0, max = ~0, val;
307 spl_ctl_table dummy = *table;
308 SENTRY;
309
310 dummy.data = &val;
311 dummy.proc_handler = &proc_dointvec;
312 dummy.extra1 = &min;
313 dummy.extra2 = &max;
314
315 if (write) {
316 *ppos += *lenp;
317 } else {
318 # ifdef HAVE_ATOMIC64_T
319 val = atomic64_read((atomic64_t *)table->data);
320 # else
321 val = atomic_read((atomic_t *)table->data);
322 # endif /* HAVE_ATOMIC64_T */
323 rc = spl_proc_doulongvec_minmax(&dummy, write, filp,
324 buffer, lenp, ppos);
325 }
326
327 SRETURN(rc);
328 }
329
330 SPL_PROC_HANDLER(proc_doslab)
331 {
332 int rc = 0;
333 unsigned long min = 0, max = ~0, val = 0, mask;
334 spl_ctl_table dummy = *table;
335 spl_kmem_cache_t *skc;
336 SENTRY;
337
338 dummy.data = &val;
339 dummy.proc_handler = &proc_dointvec;
340 dummy.extra1 = &min;
341 dummy.extra2 = &max;
342
343 if (write) {
344 *ppos += *lenp;
345 } else {
346 down_read(&spl_kmem_cache_sem);
347 mask = (unsigned long)table->data;
348
349 list_for_each_entry(skc, &spl_kmem_cache_list, skc_list) {
350
351 /* Only use slabs of the correct kmem/vmem type */
352 if (!(skc->skc_flags & mask))
353 continue;
354
355 /* Sum the specified field for selected slabs */
356 switch (mask & (KMC_TOTAL | KMC_ALLOC | KMC_MAX)) {
357 case KMC_TOTAL:
358 val += skc->skc_slab_size * skc->skc_slab_total;
359 break;
360 case KMC_ALLOC:
361 val += skc->skc_obj_size * skc->skc_obj_alloc;
362 break;
363 case KMC_MAX:
364 val += skc->skc_obj_size * skc->skc_obj_max;
365 break;
366 }
367 }
368
369 up_read(&spl_kmem_cache_sem);
370 rc = spl_proc_doulongvec_minmax(&dummy, write, filp,
371 buffer, lenp, ppos);
372 }
373
374 SRETURN(rc);
375 }
376 #endif /* DEBUG_KMEM */
377
378 SPL_PROC_HANDLER(proc_dohostid)
379 {
380 int len, rc = 0;
381 char *end, str[32];
382 SENTRY;
383
384 if (write) {
385 /* We can't use spl_proc_doulongvec_minmax() in the write
386 * case here because hostid while a hex value has no
387 * leading 0x which confuses the helper function. */
388 rc = proc_copyin_string(str, sizeof(str), buffer, *lenp);
389 if (rc < 0)
390 SRETURN(rc);
391
392 spl_hostid = simple_strtoul(str, &end, 16);
393 if (str == end)
394 SRETURN(-EINVAL);
395
396 } else {
397 len = snprintf(str, sizeof(str), "%lx", spl_hostid);
398 if (*ppos >= len)
399 rc = 0;
400 else
401 rc = proc_copyout_string(buffer,*lenp,str+*ppos,"\n");
402
403 if (rc >= 0) {
404 *lenp = rc;
405 *ppos += rc;
406 }
407 }
408
409 SRETURN(rc);
410 }
411
412 #ifdef DEBUG_KMEM
413 static void
414 slab_seq_show_headers(struct seq_file *f)
415 {
416 seq_printf(f,
417 "--------------------- cache ----------"
418 "--------------------------------------------- "
419 "----- slab ------ "
420 "---- object ----- "
421 "--- emergency ---\n");
422 seq_printf(f,
423 "name "
424 " flags size alloc slabsize objsize "
425 "total alloc max "
426 "total alloc max "
427 "dlock alloc max\n");
428 }
429
430 static int
431 slab_seq_show(struct seq_file *f, void *p)
432 {
433 spl_kmem_cache_t *skc = p;
434
435 ASSERT(skc->skc_magic == SKC_MAGIC);
436
437 /*
438 * Backed by Linux slab see /proc/slabinfo.
439 */
440 if (skc->skc_flags & KMC_SLAB)
441 return (0);
442
443 spin_lock(&skc->skc_lock);
444 seq_printf(f, "%-36s ", skc->skc_name);
445 seq_printf(f, "0x%05lx %9lu %9lu %8u %8u "
446 "%5lu %5lu %5lu %5lu %5lu %5lu %5lu %5lu %5lu\n",
447 (long unsigned)skc->skc_flags,
448 (long unsigned)(skc->skc_slab_size * skc->skc_slab_total),
449 (long unsigned)(skc->skc_obj_size * skc->skc_obj_alloc),
450 (unsigned)skc->skc_slab_size,
451 (unsigned)skc->skc_obj_size,
452 (long unsigned)skc->skc_slab_total,
453 (long unsigned)skc->skc_slab_alloc,
454 (long unsigned)skc->skc_slab_max,
455 (long unsigned)skc->skc_obj_total,
456 (long unsigned)skc->skc_obj_alloc,
457 (long unsigned)skc->skc_obj_max,
458 (long unsigned)skc->skc_obj_deadlock,
459 (long unsigned)skc->skc_obj_emergency,
460 (long unsigned)skc->skc_obj_emergency_max);
461
462 spin_unlock(&skc->skc_lock);
463
464 return 0;
465 }
466
467 static void *
468 slab_seq_start(struct seq_file *f, loff_t *pos)
469 {
470 struct list_head *p;
471 loff_t n = *pos;
472 SENTRY;
473
474 down_read(&spl_kmem_cache_sem);
475 if (!n)
476 slab_seq_show_headers(f);
477
478 p = spl_kmem_cache_list.next;
479 while (n--) {
480 p = p->next;
481 if (p == &spl_kmem_cache_list)
482 SRETURN(NULL);
483 }
484
485 SRETURN(list_entry(p, spl_kmem_cache_t, skc_list));
486 }
487
488 static void *
489 slab_seq_next(struct seq_file *f, void *p, loff_t *pos)
490 {
491 spl_kmem_cache_t *skc = p;
492 SENTRY;
493
494 ++*pos;
495 SRETURN((skc->skc_list.next == &spl_kmem_cache_list) ?
496 NULL : list_entry(skc->skc_list.next,spl_kmem_cache_t,skc_list));
497 }
498
499 static void
500 slab_seq_stop(struct seq_file *f, void *v)
501 {
502 up_read(&spl_kmem_cache_sem);
503 }
504
505 static struct seq_operations slab_seq_ops = {
506 .show = slab_seq_show,
507 .start = slab_seq_start,
508 .next = slab_seq_next,
509 .stop = slab_seq_stop,
510 };
511
512 static int
513 proc_slab_open(struct inode *inode, struct file *filp)
514 {
515 return seq_open(filp, &slab_seq_ops);
516 }
517
518 static struct file_operations proc_slab_operations = {
519 .open = proc_slab_open,
520 .read = seq_read,
521 .llseek = seq_lseek,
522 .release = seq_release,
523 };
524 #endif /* DEBUG_KMEM */
525
526 #ifdef DEBUG_LOG
527 static struct ctl_table spl_debug_table[] = {
528 {
529 .procname = "subsystem",
530 .data = &spl_debug_subsys,
531 .maxlen = sizeof(unsigned long),
532 .mode = 0644,
533 .proc_handler = &proc_dobitmasks
534 },
535 {
536 .procname = "mask",
537 .data = &spl_debug_mask,
538 .maxlen = sizeof(unsigned long),
539 .mode = 0644,
540 .proc_handler = &proc_dobitmasks
541 },
542 {
543 .procname = "printk",
544 .data = &spl_debug_printk,
545 .maxlen = sizeof(unsigned long),
546 .mode = 0644,
547 .proc_handler = &proc_dobitmasks
548 },
549 {
550 .procname = "mb",
551 .mode = 0644,
552 .proc_handler = &proc_debug_mb,
553 },
554 {
555 .procname = "binary",
556 .data = &spl_debug_binary,
557 .maxlen = sizeof(int),
558 .mode = 0644,
559 .proc_handler = &proc_dointvec,
560 },
561 {
562 .procname = "catastrophe",
563 .data = &spl_debug_catastrophe,
564 .maxlen = sizeof(int),
565 .mode = 0444,
566 .proc_handler = &proc_dointvec,
567 },
568 {
569 .procname = "panic_on_bug",
570 .data = &spl_debug_panic_on_bug,
571 .maxlen = sizeof(int),
572 .mode = 0644,
573 .proc_handler = &proc_dointvec
574 },
575 {
576 .procname = "path",
577 .data = spl_debug_file_path,
578 .maxlen = sizeof(spl_debug_file_path),
579 .mode = 0644,
580 .proc_handler = &proc_dostring,
581 },
582 {
583 .procname = "dump",
584 .mode = 0200,
585 .proc_handler = &proc_dump_kernel,
586 },
587 {
588 .procname = "force_bug",
589 .mode = 0200,
590 .proc_handler = &proc_force_bug,
591 },
592 {
593 .procname = "console_ratelimit",
594 .data = &spl_console_ratelimit,
595 .maxlen = sizeof(int),
596 .mode = 0644,
597 .proc_handler = &proc_dointvec,
598 },
599 {
600 .procname = "console_max_delay_centisecs",
601 .maxlen = sizeof(int),
602 .mode = 0644,
603 .proc_handler = &proc_console_max_delay_cs,
604 },
605 {
606 .procname = "console_min_delay_centisecs",
607 .maxlen = sizeof(int),
608 .mode = 0644,
609 .proc_handler = &proc_console_min_delay_cs,
610 },
611 {
612 .procname = "console_backoff",
613 .maxlen = sizeof(int),
614 .mode = 0644,
615 .proc_handler = &proc_console_backoff,
616 },
617 {
618 .procname = "stack_max",
619 .data = &spl_debug_stack,
620 .maxlen = sizeof(int),
621 .mode = 0444,
622 .proc_handler = &proc_dointvec,
623 },
624 {0},
625 };
626 #endif /* DEBUG_LOG */
627
628 #ifdef DEBUG_KMEM
629 static struct ctl_table spl_kmem_table[] = {
630 {
631 .procname = "kmem_used",
632 .data = &kmem_alloc_used,
633 # ifdef HAVE_ATOMIC64_T
634 .maxlen = sizeof(atomic64_t),
635 # else
636 .maxlen = sizeof(atomic_t),
637 # endif /* HAVE_ATOMIC64_T */
638 .mode = 0444,
639 .proc_handler = &proc_domemused,
640 },
641 {
642 .procname = "kmem_max",
643 .data = &kmem_alloc_max,
644 .maxlen = sizeof(unsigned long),
645 .extra1 = &table_min,
646 .extra2 = &table_max,
647 .mode = 0444,
648 .proc_handler = &proc_doulongvec_minmax,
649 },
650 {
651 .procname = "vmem_used",
652 .data = &vmem_alloc_used,
653 # ifdef HAVE_ATOMIC64_T
654 .maxlen = sizeof(atomic64_t),
655 # else
656 .maxlen = sizeof(atomic_t),
657 # endif /* HAVE_ATOMIC64_T */
658 .mode = 0444,
659 .proc_handler = &proc_domemused,
660 },
661 {
662 .procname = "vmem_max",
663 .data = &vmem_alloc_max,
664 .maxlen = sizeof(unsigned long),
665 .extra1 = &table_min,
666 .extra2 = &table_max,
667 .mode = 0444,
668 .proc_handler = &proc_doulongvec_minmax,
669 },
670 {
671 .procname = "slab_kmem_total",
672 .data = (void *)(KMC_KMEM | KMC_TOTAL),
673 .maxlen = sizeof(unsigned long),
674 .extra1 = &table_min,
675 .extra2 = &table_max,
676 .mode = 0444,
677 .proc_handler = &proc_doslab,
678 },
679 {
680 .procname = "slab_kmem_alloc",
681 .data = (void *)(KMC_KMEM | KMC_ALLOC),
682 .maxlen = sizeof(unsigned long),
683 .extra1 = &table_min,
684 .extra2 = &table_max,
685 .mode = 0444,
686 .proc_handler = &proc_doslab,
687 },
688 {
689 .procname = "slab_kmem_max",
690 .data = (void *)(KMC_KMEM | KMC_MAX),
691 .maxlen = sizeof(unsigned long),
692 .extra1 = &table_min,
693 .extra2 = &table_max,
694 .mode = 0444,
695 .proc_handler = &proc_doslab,
696 },
697 {
698 .procname = "slab_vmem_total",
699 .data = (void *)(KMC_VMEM | KMC_TOTAL),
700 .maxlen = sizeof(unsigned long),
701 .extra1 = &table_min,
702 .extra2 = &table_max,
703 .mode = 0444,
704 .proc_handler = &proc_doslab,
705 },
706 {
707 .procname = "slab_vmem_alloc",
708 .data = (void *)(KMC_VMEM | KMC_ALLOC),
709 .maxlen = sizeof(unsigned long),
710 .extra1 = &table_min,
711 .extra2 = &table_max,
712 .mode = 0444,
713 .proc_handler = &proc_doslab,
714 },
715 {
716 .procname = "slab_vmem_max",
717 .data = (void *)(KMC_VMEM | KMC_MAX),
718 .maxlen = sizeof(unsigned long),
719 .extra1 = &table_min,
720 .extra2 = &table_max,
721 .mode = 0444,
722 .proc_handler = &proc_doslab,
723 },
724 {0},
725 };
726 #endif /* DEBUG_KMEM */
727
728 static struct ctl_table spl_kstat_table[] = {
729 {0},
730 };
731
732 static struct ctl_table spl_table[] = {
733 /* NB No .strategy entries have been provided since
734 * sysctl(8) prefers to go via /proc for portability.
735 */
736 {
737 .procname = "version",
738 .data = spl_version,
739 .maxlen = sizeof(spl_version),
740 .mode = 0444,
741 .proc_handler = &proc_dostring,
742 },
743 {
744 .procname = "hostid",
745 .data = &spl_hostid,
746 .maxlen = sizeof(unsigned long),
747 .mode = 0644,
748 .proc_handler = &proc_dohostid,
749 },
750 #ifdef DEBUG_LOG
751 {
752 .procname = "debug",
753 .mode = 0555,
754 .child = spl_debug_table,
755 },
756 #endif
757 #ifdef DEBUG_KMEM
758 {
759 .procname = "kmem",
760 .mode = 0555,
761 .child = spl_kmem_table,
762 },
763 #endif
764 {
765 .procname = "kstat",
766 .mode = 0555,
767 .child = spl_kstat_table,
768 },
769 { 0 },
770 };
771
772 static struct ctl_table spl_dir[] = {
773 {
774 .procname = "spl",
775 .mode = 0555,
776 .child = spl_table,
777 },
778 { 0 }
779 };
780
781 static struct ctl_table spl_root[] = {
782 {
783 #ifdef HAVE_CTL_NAME
784 .ctl_name = CTL_KERN,
785 #endif
786 .procname = "kernel",
787 .mode = 0555,
788 .child = spl_dir,
789 },
790 { 0 }
791 };
792
793 int
794 spl_proc_init(void)
795 {
796 int rc = 0;
797 SENTRY;
798
799 spl_header = register_sysctl_table(spl_root);
800 if (spl_header == NULL)
801 SRETURN(-EUNATCH);
802
803 proc_spl = proc_mkdir("spl", NULL);
804 if (proc_spl == NULL)
805 SGOTO(out, rc = -EUNATCH);
806
807 #ifdef DEBUG_KMEM
808 proc_spl_kmem = proc_mkdir("kmem", proc_spl);
809 if (proc_spl_kmem == NULL)
810 SGOTO(out, rc = -EUNATCH);
811
812 proc_spl_kmem_slab = proc_create_data("slab", 0444,
813 proc_spl_kmem, &proc_slab_operations, NULL);
814 if (proc_spl_kmem_slab == NULL)
815 SGOTO(out, rc = -EUNATCH);
816
817 #endif /* DEBUG_KMEM */
818
819 proc_spl_kstat = proc_mkdir("kstat", proc_spl);
820 if (proc_spl_kstat == NULL)
821 SGOTO(out, rc = -EUNATCH);
822 out:
823 if (rc) {
824 remove_proc_entry("kstat", proc_spl);
825 #ifdef DEBUG_KMEM
826 remove_proc_entry("slab", proc_spl_kmem);
827 remove_proc_entry("kmem", proc_spl);
828 #endif
829 remove_proc_entry("spl", NULL);
830 unregister_sysctl_table(spl_header);
831 }
832
833 SRETURN(rc);
834 }
835
836 void
837 spl_proc_fini(void)
838 {
839 SENTRY;
840
841 remove_proc_entry("kstat", proc_spl);
842 #ifdef DEBUG_KMEM
843 remove_proc_entry("slab", proc_spl_kmem);
844 remove_proc_entry("kmem", proc_spl);
845 #endif
846 remove_proc_entry("spl", NULL);
847
848 ASSERT(spl_header != NULL);
849 unregister_sysctl_table(spl_header);
850
851 SEXIT;
852 }