]> git.proxmox.com Git - mirror_spl.git/blob - module/spl/spl-proc.c
Remove CTL_UNNUMBERED sysctl interface
[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 #ifndef HAVE_KALLSYMS_LOOKUP_NAME
413 SPL_PROC_HANDLER(proc_dokallsyms_lookup_name)
414 {
415 int len, rc = 0;
416 char *end, str[32];
417 SENTRY;
418
419 if (write) {
420 /* This may only be set once at module load time */
421 if (spl_kallsyms_lookup_name_fn != SYMBOL_POISON)
422 SRETURN(-EEXIST);
423
424 /* We can't use spl_proc_doulongvec_minmax() in the write
425 * case here because the address while a hex value has no
426 * leading 0x which confuses the helper function. */
427 rc = proc_copyin_string(str, sizeof(str), buffer, *lenp);
428 if (rc < 0)
429 SRETURN(rc);
430
431 spl_kallsyms_lookup_name_fn =
432 (kallsyms_lookup_name_t)simple_strtoul(str, &end, 16);
433 wake_up(&spl_kallsyms_lookup_name_waitq);
434
435 if (str == end)
436 SRETURN(-EINVAL);
437
438 *ppos += *lenp;
439 } else {
440 len = snprintf(str, sizeof(str), "%lx",
441 (unsigned long)spl_kallsyms_lookup_name_fn);
442 if (*ppos >= len)
443 rc = 0;
444 else
445 rc = proc_copyout_string(buffer,*lenp,str+*ppos,"\n");
446
447 if (rc >= 0) {
448 *lenp = rc;
449 *ppos += rc;
450 }
451 }
452
453 SRETURN(rc);
454 }
455 #endif /* HAVE_KALLSYMS_LOOKUP_NAME */
456
457 SPL_PROC_HANDLER(proc_doavailrmem)
458 {
459 int len, rc = 0;
460 char str[32];
461 SENTRY;
462
463 if (write) {
464 *ppos += *lenp;
465 } else {
466 len = snprintf(str, sizeof(str), "%lu",
467 (unsigned long)availrmem);
468 if (*ppos >= len)
469 rc = 0;
470 else
471 rc = proc_copyout_string(buffer,*lenp,str+*ppos,"\n");
472
473 if (rc >= 0) {
474 *lenp = rc;
475 *ppos += rc;
476 }
477 }
478
479 SRETURN(rc);
480 }
481
482 SPL_PROC_HANDLER(proc_dofreemem)
483 {
484 int len, rc = 0;
485 char str[32];
486 SENTRY;
487
488 if (write) {
489 *ppos += *lenp;
490 } else {
491 len = snprintf(str, sizeof(str), "%lu", (unsigned long)freemem);
492 if (*ppos >= len)
493 rc = 0;
494 else
495 rc = proc_copyout_string(buffer,*lenp,str+*ppos,"\n");
496
497 if (rc >= 0) {
498 *lenp = rc;
499 *ppos += rc;
500 }
501 }
502
503 SRETURN(rc);
504 }
505
506 #ifdef DEBUG_KMEM
507 static void
508 slab_seq_show_headers(struct seq_file *f)
509 {
510 seq_printf(f,
511 "--------------------- cache ----------"
512 "--------------------------------------------- "
513 "----- slab ------ "
514 "---- object ----- "
515 "--- emergency ---\n");
516 seq_printf(f,
517 "name "
518 " flags size alloc slabsize objsize "
519 "total alloc max "
520 "total alloc max "
521 "dlock alloc max\n");
522 }
523
524 static int
525 slab_seq_show(struct seq_file *f, void *p)
526 {
527 spl_kmem_cache_t *skc = p;
528
529 ASSERT(skc->skc_magic == SKC_MAGIC);
530
531 /*
532 * Backed by Linux slab see /proc/slabinfo.
533 */
534 if (skc->skc_flags & KMC_SLAB)
535 return (0);
536
537 spin_lock(&skc->skc_lock);
538 seq_printf(f, "%-36s ", skc->skc_name);
539 seq_printf(f, "0x%05lx %9lu %9lu %8u %8u "
540 "%5lu %5lu %5lu %5lu %5lu %5lu %5lu %5lu %5lu\n",
541 (long unsigned)skc->skc_flags,
542 (long unsigned)(skc->skc_slab_size * skc->skc_slab_total),
543 (long unsigned)(skc->skc_obj_size * skc->skc_obj_alloc),
544 (unsigned)skc->skc_slab_size,
545 (unsigned)skc->skc_obj_size,
546 (long unsigned)skc->skc_slab_total,
547 (long unsigned)skc->skc_slab_alloc,
548 (long unsigned)skc->skc_slab_max,
549 (long unsigned)skc->skc_obj_total,
550 (long unsigned)skc->skc_obj_alloc,
551 (long unsigned)skc->skc_obj_max,
552 (long unsigned)skc->skc_obj_deadlock,
553 (long unsigned)skc->skc_obj_emergency,
554 (long unsigned)skc->skc_obj_emergency_max);
555
556 spin_unlock(&skc->skc_lock);
557
558 return 0;
559 }
560
561 static void *
562 slab_seq_start(struct seq_file *f, loff_t *pos)
563 {
564 struct list_head *p;
565 loff_t n = *pos;
566 SENTRY;
567
568 down_read(&spl_kmem_cache_sem);
569 if (!n)
570 slab_seq_show_headers(f);
571
572 p = spl_kmem_cache_list.next;
573 while (n--) {
574 p = p->next;
575 if (p == &spl_kmem_cache_list)
576 SRETURN(NULL);
577 }
578
579 SRETURN(list_entry(p, spl_kmem_cache_t, skc_list));
580 }
581
582 static void *
583 slab_seq_next(struct seq_file *f, void *p, loff_t *pos)
584 {
585 spl_kmem_cache_t *skc = p;
586 SENTRY;
587
588 ++*pos;
589 SRETURN((skc->skc_list.next == &spl_kmem_cache_list) ?
590 NULL : list_entry(skc->skc_list.next,spl_kmem_cache_t,skc_list));
591 }
592
593 static void
594 slab_seq_stop(struct seq_file *f, void *v)
595 {
596 up_read(&spl_kmem_cache_sem);
597 }
598
599 static struct seq_operations slab_seq_ops = {
600 .show = slab_seq_show,
601 .start = slab_seq_start,
602 .next = slab_seq_next,
603 .stop = slab_seq_stop,
604 };
605
606 static int
607 proc_slab_open(struct inode *inode, struct file *filp)
608 {
609 return seq_open(filp, &slab_seq_ops);
610 }
611
612 static struct file_operations proc_slab_operations = {
613 .open = proc_slab_open,
614 .read = seq_read,
615 .llseek = seq_lseek,
616 .release = seq_release,
617 };
618 #endif /* DEBUG_KMEM */
619
620 #ifdef DEBUG_LOG
621 static struct ctl_table spl_debug_table[] = {
622 {
623 .procname = "subsystem",
624 .data = &spl_debug_subsys,
625 .maxlen = sizeof(unsigned long),
626 .mode = 0644,
627 .proc_handler = &proc_dobitmasks
628 },
629 {
630 .procname = "mask",
631 .data = &spl_debug_mask,
632 .maxlen = sizeof(unsigned long),
633 .mode = 0644,
634 .proc_handler = &proc_dobitmasks
635 },
636 {
637 .procname = "printk",
638 .data = &spl_debug_printk,
639 .maxlen = sizeof(unsigned long),
640 .mode = 0644,
641 .proc_handler = &proc_dobitmasks
642 },
643 {
644 .procname = "mb",
645 .mode = 0644,
646 .proc_handler = &proc_debug_mb,
647 },
648 {
649 .procname = "binary",
650 .data = &spl_debug_binary,
651 .maxlen = sizeof(int),
652 .mode = 0644,
653 .proc_handler = &proc_dointvec,
654 },
655 {
656 .procname = "catastrophe",
657 .data = &spl_debug_catastrophe,
658 .maxlen = sizeof(int),
659 .mode = 0444,
660 .proc_handler = &proc_dointvec,
661 },
662 {
663 .procname = "panic_on_bug",
664 .data = &spl_debug_panic_on_bug,
665 .maxlen = sizeof(int),
666 .mode = 0644,
667 .proc_handler = &proc_dointvec
668 },
669 {
670 .procname = "path",
671 .data = spl_debug_file_path,
672 .maxlen = sizeof(spl_debug_file_path),
673 .mode = 0644,
674 .proc_handler = &proc_dostring,
675 },
676 {
677 .procname = "dump",
678 .mode = 0200,
679 .proc_handler = &proc_dump_kernel,
680 },
681 {
682 .procname = "force_bug",
683 .mode = 0200,
684 .proc_handler = &proc_force_bug,
685 },
686 {
687 .procname = "console_ratelimit",
688 .data = &spl_console_ratelimit,
689 .maxlen = sizeof(int),
690 .mode = 0644,
691 .proc_handler = &proc_dointvec,
692 },
693 {
694 .procname = "console_max_delay_centisecs",
695 .maxlen = sizeof(int),
696 .mode = 0644,
697 .proc_handler = &proc_console_max_delay_cs,
698 },
699 {
700 .procname = "console_min_delay_centisecs",
701 .maxlen = sizeof(int),
702 .mode = 0644,
703 .proc_handler = &proc_console_min_delay_cs,
704 },
705 {
706 .procname = "console_backoff",
707 .maxlen = sizeof(int),
708 .mode = 0644,
709 .proc_handler = &proc_console_backoff,
710 },
711 {
712 .procname = "stack_max",
713 .data = &spl_debug_stack,
714 .maxlen = sizeof(int),
715 .mode = 0444,
716 .proc_handler = &proc_dointvec,
717 },
718 {0},
719 };
720 #endif /* DEBUG_LOG */
721
722 static struct ctl_table spl_vm_table[] = {
723 {
724 .procname = "minfree",
725 .data = &minfree,
726 .maxlen = sizeof(int),
727 .mode = 0644,
728 .proc_handler = &proc_dointvec,
729 },
730 {
731 .procname = "desfree",
732 .data = &desfree,
733 .maxlen = sizeof(int),
734 .mode = 0644,
735 .proc_handler = &proc_dointvec,
736 },
737 {
738 .procname = "lotsfree",
739 .data = &lotsfree,
740 .maxlen = sizeof(int),
741 .mode = 0644,
742 .proc_handler = &proc_dointvec,
743 },
744 {
745 .procname = "needfree",
746 .data = &needfree,
747 .maxlen = sizeof(int),
748 .mode = 0444,
749 .proc_handler = &proc_dointvec,
750 },
751 {
752 .procname = "swapfs_minfree",
753 .data = &swapfs_minfree,
754 .maxlen = sizeof(int),
755 .mode = 0644,
756 .proc_handler = &proc_dointvec,
757 },
758 {
759 .procname = "swapfs_reserve",
760 .data = &swapfs_reserve,
761 .maxlen = sizeof(int),
762 .mode = 0644,
763 .proc_handler = &proc_dointvec,
764 },
765 {
766 .procname = "availrmem",
767 .mode = 0444,
768 .proc_handler = &proc_doavailrmem,
769 },
770 {
771 .procname = "freemem",
772 .data = (void *)2,
773 .maxlen = sizeof(int),
774 .mode = 0444,
775 .proc_handler = &proc_dofreemem,
776 },
777 {
778 .procname = "physmem",
779 .data = &physmem,
780 .maxlen = sizeof(int),
781 .mode = 0444,
782 .proc_handler = &proc_dointvec,
783 },
784 {0},
785 };
786
787 #ifdef DEBUG_KMEM
788 static struct ctl_table spl_kmem_table[] = {
789 {
790 .procname = "kmem_used",
791 .data = &kmem_alloc_used,
792 # ifdef HAVE_ATOMIC64_T
793 .maxlen = sizeof(atomic64_t),
794 # else
795 .maxlen = sizeof(atomic_t),
796 # endif /* HAVE_ATOMIC64_T */
797 .mode = 0444,
798 .proc_handler = &proc_domemused,
799 },
800 {
801 .procname = "kmem_max",
802 .data = &kmem_alloc_max,
803 .maxlen = sizeof(unsigned long),
804 .extra1 = &table_min,
805 .extra2 = &table_max,
806 .mode = 0444,
807 .proc_handler = &proc_doulongvec_minmax,
808 },
809 {
810 .procname = "vmem_used",
811 .data = &vmem_alloc_used,
812 # ifdef HAVE_ATOMIC64_T
813 .maxlen = sizeof(atomic64_t),
814 # else
815 .maxlen = sizeof(atomic_t),
816 # endif /* HAVE_ATOMIC64_T */
817 .mode = 0444,
818 .proc_handler = &proc_domemused,
819 },
820 {
821 .procname = "vmem_max",
822 .data = &vmem_alloc_max,
823 .maxlen = sizeof(unsigned long),
824 .extra1 = &table_min,
825 .extra2 = &table_max,
826 .mode = 0444,
827 .proc_handler = &proc_doulongvec_minmax,
828 },
829 {
830 .procname = "slab_kmem_total",
831 .data = (void *)(KMC_KMEM | KMC_TOTAL),
832 .maxlen = sizeof(unsigned long),
833 .extra1 = &table_min,
834 .extra2 = &table_max,
835 .mode = 0444,
836 .proc_handler = &proc_doslab,
837 },
838 {
839 .procname = "slab_kmem_alloc",
840 .data = (void *)(KMC_KMEM | KMC_ALLOC),
841 .maxlen = sizeof(unsigned long),
842 .extra1 = &table_min,
843 .extra2 = &table_max,
844 .mode = 0444,
845 .proc_handler = &proc_doslab,
846 },
847 {
848 .procname = "slab_kmem_max",
849 .data = (void *)(KMC_KMEM | KMC_MAX),
850 .maxlen = sizeof(unsigned long),
851 .extra1 = &table_min,
852 .extra2 = &table_max,
853 .mode = 0444,
854 .proc_handler = &proc_doslab,
855 },
856 {
857 .procname = "slab_vmem_total",
858 .data = (void *)(KMC_VMEM | KMC_TOTAL),
859 .maxlen = sizeof(unsigned long),
860 .extra1 = &table_min,
861 .extra2 = &table_max,
862 .mode = 0444,
863 .proc_handler = &proc_doslab,
864 },
865 {
866 .procname = "slab_vmem_alloc",
867 .data = (void *)(KMC_VMEM | KMC_ALLOC),
868 .maxlen = sizeof(unsigned long),
869 .extra1 = &table_min,
870 .extra2 = &table_max,
871 .mode = 0444,
872 .proc_handler = &proc_doslab,
873 },
874 {
875 .procname = "slab_vmem_max",
876 .data = (void *)(KMC_VMEM | KMC_MAX),
877 .maxlen = sizeof(unsigned long),
878 .extra1 = &table_min,
879 .extra2 = &table_max,
880 .mode = 0444,
881 .proc_handler = &proc_doslab,
882 },
883 {0},
884 };
885 #endif /* DEBUG_KMEM */
886
887 static struct ctl_table spl_kstat_table[] = {
888 {0},
889 };
890
891 static struct ctl_table spl_table[] = {
892 /* NB No .strategy entries have been provided since
893 * sysctl(8) prefers to go via /proc for portability.
894 */
895 {
896 .procname = "version",
897 .data = spl_version,
898 .maxlen = sizeof(spl_version),
899 .mode = 0444,
900 .proc_handler = &proc_dostring,
901 },
902 {
903 .procname = "hostid",
904 .data = &spl_hostid,
905 .maxlen = sizeof(unsigned long),
906 .mode = 0644,
907 .proc_handler = &proc_dohostid,
908 },
909 #ifndef HAVE_KALLSYMS_LOOKUP_NAME
910 {
911 .procname = "kallsyms_lookup_name",
912 .data = &spl_kallsyms_lookup_name_fn,
913 .maxlen = sizeof(unsigned long),
914 .mode = 0644,
915 .proc_handler = &proc_dokallsyms_lookup_name,
916 },
917 #endif
918 #ifdef DEBUG_LOG
919 {
920 .procname = "debug",
921 .mode = 0555,
922 .child = spl_debug_table,
923 },
924 #endif
925 {
926 .procname = "vm",
927 .mode = 0555,
928 .child = spl_vm_table,
929 },
930 #ifdef DEBUG_KMEM
931 {
932 .procname = "kmem",
933 .mode = 0555,
934 .child = spl_kmem_table,
935 },
936 #endif
937 {
938 .procname = "kstat",
939 .mode = 0555,
940 .child = spl_kstat_table,
941 },
942 { 0 },
943 };
944
945 static struct ctl_table spl_dir[] = {
946 {
947 .procname = "spl",
948 .mode = 0555,
949 .child = spl_table,
950 },
951 { 0 }
952 };
953
954 static struct ctl_table spl_root[] = {
955 {
956 #ifdef HAVE_CTL_NAME
957 .ctl_name = CTL_KERN,
958 #endif
959 .procname = "kernel",
960 .mode = 0555,
961 .child = spl_dir,
962 },
963 { 0 }
964 };
965
966 int
967 spl_proc_init(void)
968 {
969 int rc = 0;
970 SENTRY;
971
972 spl_header = register_sysctl_table(spl_root);
973 if (spl_header == NULL)
974 SRETURN(-EUNATCH);
975
976 proc_spl = proc_mkdir("spl", NULL);
977 if (proc_spl == NULL)
978 SGOTO(out, rc = -EUNATCH);
979
980 #ifdef DEBUG_KMEM
981 proc_spl_kmem = proc_mkdir("kmem", proc_spl);
982 if (proc_spl_kmem == NULL)
983 SGOTO(out, rc = -EUNATCH);
984
985 proc_spl_kmem_slab = proc_create_data("slab", 0444,
986 proc_spl_kmem, &proc_slab_operations, NULL);
987 if (proc_spl_kmem_slab == NULL)
988 SGOTO(out, rc = -EUNATCH);
989
990 #endif /* DEBUG_KMEM */
991
992 proc_spl_kstat = proc_mkdir("kstat", proc_spl);
993 if (proc_spl_kstat == NULL)
994 SGOTO(out, rc = -EUNATCH);
995 out:
996 if (rc) {
997 remove_proc_entry("kstat", proc_spl);
998 #ifdef DEBUG_KMEM
999 remove_proc_entry("slab", proc_spl_kmem);
1000 remove_proc_entry("kmem", proc_spl);
1001 #endif
1002 remove_proc_entry("spl", NULL);
1003 unregister_sysctl_table(spl_header);
1004 }
1005
1006 SRETURN(rc);
1007 }
1008
1009 void
1010 spl_proc_fini(void)
1011 {
1012 SENTRY;
1013
1014 remove_proc_entry("kstat", proc_spl);
1015 #ifdef DEBUG_KMEM
1016 remove_proc_entry("slab", proc_spl_kmem);
1017 remove_proc_entry("kmem", proc_spl);
1018 #endif
1019 remove_proc_entry("spl", NULL);
1020
1021 ASSERT(spl_header != NULL);
1022 unregister_sysctl_table(spl_header);
1023
1024 SEXIT;
1025 }