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