]> git.proxmox.com Git - mirror_zfs.git/blob - module/spl/spl-proc.c
277a92a7af1f08da2d2687daf5b29acc89adce44
[mirror_zfs.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://github.com/behlendorf/spl/>.
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
33 #ifdef DEBUG_SUBSYSTEM
34 #undef DEBUG_SUBSYSTEM
35 #endif
36
37 #define DEBUG_SUBSYSTEM S_PROC
38
39 #ifdef DEBUG_KMEM
40 static unsigned long table_min = 0;
41 static unsigned long table_max = ~0;
42 #endif
43
44 #ifdef CONFIG_SYSCTL
45 static struct ctl_table_header *spl_header = NULL;
46 #endif /* CONFIG_SYSCTL */
47
48 static struct proc_dir_entry *proc_spl = NULL;
49 #ifdef DEBUG_KMEM
50 static struct proc_dir_entry *proc_spl_kmem = NULL;
51 static struct proc_dir_entry *proc_spl_kmem_slab = NULL;
52 #endif /* DEBUG_KMEM */
53 struct proc_dir_entry *proc_spl_kstat = NULL;
54
55 #ifdef HAVE_CTL_UNNUMBERED
56
57 #define CTL_SPL CTL_UNNUMBERED
58 #define CTL_SPL_DEBUG CTL_UNNUMBERED
59 #define CTL_SPL_VM CTL_UNNUMBERED
60 #define CTL_SPL_MUTEX CTL_UNNUMBERED
61 #define CTL_SPL_KMEM CTL_UNNUMBERED
62 #define CTL_SPL_KSTAT CTL_UNNUMBERED
63
64 #define CTL_VERSION CTL_UNNUMBERED /* Version */
65 #define CTL_HOSTID CTL_UNNUMBERED /* Host id by /usr/bin/hostid */
66 #define CTL_HW_SERIAL CTL_UNNUMBERED /* HW serial number by hostid */
67 #define CTL_KALLSYMS CTL_UNNUMBERED /* kallsyms_lookup_name addr */
68
69 #define CTL_DEBUG_SUBSYS CTL_UNNUMBERED /* Debug subsystem */
70 #define CTL_DEBUG_MASK CTL_UNNUMBERED /* Debug mask */
71 #define CTL_DEBUG_PRINTK CTL_UNNUMBERED /* All messages to console */
72 #define CTL_DEBUG_MB CTL_UNNUMBERED /* Debug buffer size */
73 #define CTL_DEBUG_BINARY CTL_UNNUMBERED /* Binary data in buffer */
74 #define CTL_DEBUG_CATASTROPHE CTL_UNNUMBERED /* Set if BUG'd or panic'd */
75 #define CTL_DEBUG_PANIC_ON_BUG CTL_UNNUMBERED /* Should panic on BUG */
76 #define CTL_DEBUG_PATH CTL_UNNUMBERED /* Dump log location */
77 #define CTL_DEBUG_DUMP CTL_UNNUMBERED /* Dump debug buffer to file */
78 #define CTL_DEBUG_FORCE_BUG CTL_UNNUMBERED /* Hook to force a BUG */
79 #define CTL_DEBUG_STACK_SIZE CTL_UNNUMBERED /* Max observed stack size */
80
81 #define CTL_CONSOLE_RATELIMIT CTL_UNNUMBERED /* Ratelimit console messages */
82 #define CTL_CONSOLE_MAX_DELAY_CS CTL_UNNUMBERED /* Max delay skip messages */
83 #define CTL_CONSOLE_MIN_DELAY_CS CTL_UNNUMBERED /* Init delay skip messages */
84 #define CTL_CONSOLE_BACKOFF CTL_UNNUMBERED /* Delay increase factor */
85
86 #define CTL_VM_MINFREE CTL_UNNUMBERED /* Minimum free memory */
87 #define CTL_VM_DESFREE CTL_UNNUMBERED /* Desired free memory */
88 #define CTL_VM_LOTSFREE CTL_UNNUMBERED /* Lots of free memory */
89 #define CTL_VM_NEEDFREE CTL_UNNUMBERED /* Need free memory */
90 #define CTL_VM_SWAPFS_MINFREE CTL_UNNUMBERED /* Minimum swapfs memory */
91 #define CTL_VM_SWAPFS_RESERVE CTL_UNNUMBERED /* Reserved swapfs memory */
92 #define CTL_VM_AVAILRMEM CTL_UNNUMBERED /* Easily available memory */
93 #define CTL_VM_FREEMEM CTL_UNNUMBERED /* Free memory */
94 #define CTL_VM_PHYSMEM CTL_UNNUMBERED /* Total physical memory */
95
96 #ifdef DEBUG_KMEM
97 #define CTL_KMEM_KMEMUSED CTL_UNNUMBERED /* Alloc'd kmem bytes */
98 #define CTL_KMEM_KMEMMAX CTL_UNNUMBERED /* Max alloc'd by kmem bytes */
99 #define CTL_KMEM_VMEMUSED CTL_UNNUMBERED /* Alloc'd vmem bytes */
100 #define CTL_KMEM_VMEMMAX CTL_UNNUMBERED /* Max alloc'd by vmem bytes */
101 #define CTL_KMEM_ALLOC_FAILED CTL_UNNUMBERED /* Cache allocations failed */
102 #endif
103
104 #else /* HAVE_CTL_UNNUMBERED */
105
106 enum {
107 CTL_SPL = 0x87,
108 CTL_SPL_DEBUG = 0x88,
109 CTL_SPL_VM = 0x89,
110 CTL_SPL_MUTEX = 0x90,
111 CTL_SPL_KMEM = 0x91,
112 CTL_SPL_KSTAT = 0x92,
113 };
114
115 enum {
116 CTL_VERSION = 1, /* Version */
117 CTL_HOSTID, /* Host id reported by /usr/bin/hostid */
118 CTL_HW_SERIAL, /* Hardware serial number from hostid */
119 CTL_KALLSYMS, /* Address of kallsyms_lookup_name */
120
121 CTL_DEBUG_SUBSYS, /* Debug subsystem */
122 CTL_DEBUG_MASK, /* Debug mask */
123 CTL_DEBUG_PRINTK, /* Force all messages to console */
124 CTL_DEBUG_MB, /* Debug buffer size */
125 CTL_DEBUG_BINARY, /* Include binary data in buffer */
126 CTL_DEBUG_CATASTROPHE, /* Set if we have BUG'd or panic'd */
127 CTL_DEBUG_PANIC_ON_BUG, /* Set if we should panic on BUG */
128 CTL_DEBUG_PATH, /* Dump log location */
129 CTL_DEBUG_DUMP, /* Dump debug buffer to file */
130 CTL_DEBUG_FORCE_BUG, /* Hook to force a BUG */
131 CTL_DEBUG_STACK_SIZE, /* Max observed stack size */
132
133 CTL_CONSOLE_RATELIMIT, /* Ratelimit console messages */
134 CTL_CONSOLE_MAX_DELAY_CS, /* Max delay which we skip messages */
135 CTL_CONSOLE_MIN_DELAY_CS, /* Init delay which we skip messages */
136 CTL_CONSOLE_BACKOFF, /* Delay increase factor */
137
138 CTL_VM_MINFREE, /* Minimum free memory threshold */
139 CTL_VM_DESFREE, /* Desired free memory threshold */
140 CTL_VM_LOTSFREE, /* Lots of free memory threshold */
141 CTL_VM_NEEDFREE, /* Need free memory deficit */
142 CTL_VM_SWAPFS_MINFREE, /* Minimum swapfs memory */
143 CTL_VM_SWAPFS_RESERVE, /* Reserved swapfs memory */
144 CTL_VM_AVAILRMEM, /* Easily available memory */
145 CTL_VM_FREEMEM, /* Free memory */
146 CTL_VM_PHYSMEM, /* Total physical memory */
147
148 #ifdef DEBUG_KMEM
149 CTL_KMEM_KMEMUSED, /* Alloc'd kmem bytes */
150 CTL_KMEM_KMEMMAX, /* Max alloc'd by kmem bytes */
151 CTL_KMEM_VMEMUSED, /* Alloc'd vmem bytes */
152 CTL_KMEM_VMEMMAX, /* Max alloc'd by vmem bytes */
153 #endif
154 };
155 #endif /* HAVE_CTL_UNNUMBERED */
156
157 static int
158 proc_copyin_string(char *kbuffer, int kbuffer_size,
159 const char *ubuffer, int ubuffer_size)
160 {
161 int size;
162
163 if (ubuffer_size > kbuffer_size)
164 return -EOVERFLOW;
165
166 if (copy_from_user((void *)kbuffer, (void *)ubuffer, ubuffer_size))
167 return -EFAULT;
168
169 /* strip trailing whitespace */
170 size = strnlen(kbuffer, ubuffer_size);
171 while (size-- >= 0)
172 if (!isspace(kbuffer[size]))
173 break;
174
175 /* empty string */
176 if (size < 0)
177 return -EINVAL;
178
179 /* no space to terminate */
180 if (size == kbuffer_size)
181 return -EOVERFLOW;
182
183 kbuffer[size + 1] = 0;
184 return 0;
185 }
186
187 static int
188 proc_copyout_string(char *ubuffer, int ubuffer_size,
189 const char *kbuffer, char *append)
190 {
191 /* NB if 'append' != NULL, it's a single character to append to the
192 * copied out string - usually "\n", for /proc entries and
193 * (i.e. a terminating zero byte) for sysctl entries
194 */
195 int size = MIN(strlen(kbuffer), ubuffer_size);
196
197 if (copy_to_user(ubuffer, kbuffer, size))
198 return -EFAULT;
199
200 if (append != NULL && size < ubuffer_size) {
201 if (copy_to_user(ubuffer + size, append, 1))
202 return -EFAULT;
203
204 size++;
205 }
206
207 return size;
208 }
209
210 SPL_PROC_HANDLER(proc_dobitmasks)
211 {
212 unsigned long *mask = table->data;
213 int is_subsys = (mask == &spl_debug_subsys) ? 1 : 0;
214 int is_printk = (mask == &spl_debug_printk) ? 1 : 0;
215 int size = 512, rc;
216 char *str;
217 ENTRY;
218
219 str = kmem_alloc(size, KM_SLEEP);
220 if (str == NULL)
221 RETURN(-ENOMEM);
222
223 if (write) {
224 rc = proc_copyin_string(str, size, buffer, *lenp);
225 if (rc < 0)
226 RETURN(rc);
227
228 rc = spl_debug_str2mask(mask, str, is_subsys);
229 /* Always print BUG/ASSERT to console, so keep this mask */
230 if (is_printk)
231 *mask |= D_EMERG;
232
233 *ppos += *lenp;
234 } else {
235 rc = spl_debug_mask2str(str, size, *mask, is_subsys);
236 if (*ppos >= rc)
237 rc = 0;
238 else
239 rc = proc_copyout_string(buffer, *lenp,
240 str + *ppos, "\n");
241 if (rc >= 0) {
242 *lenp = rc;
243 *ppos += rc;
244 }
245 }
246
247 kmem_free(str, size);
248 RETURN(rc);
249 }
250
251 SPL_PROC_HANDLER(proc_debug_mb)
252 {
253 char str[32];
254 int rc, len;
255 ENTRY;
256
257 if (write) {
258 rc = proc_copyin_string(str, sizeof(str), buffer, *lenp);
259 if (rc < 0)
260 RETURN(rc);
261
262 rc = spl_debug_set_mb(simple_strtoul(str, NULL, 0));
263 *ppos += *lenp;
264 } else {
265 len = snprintf(str, sizeof(str), "%d", spl_debug_get_mb());
266 if (*ppos >= len)
267 rc = 0;
268 else
269 rc = proc_copyout_string(buffer,*lenp,str+*ppos,"\n");
270
271 if (rc >= 0) {
272 *lenp = rc;
273 *ppos += rc;
274 }
275 }
276
277 RETURN(rc);
278 }
279
280 SPL_PROC_HANDLER(proc_dump_kernel)
281 {
282 ENTRY;
283
284 if (write) {
285 spl_debug_dumplog(0);
286 *ppos += *lenp;
287 } else {
288 *lenp = 0;
289 }
290
291 RETURN(0);
292 }
293
294 SPL_PROC_HANDLER(proc_force_bug)
295 {
296 ENTRY;
297
298 if (write) {
299 CERROR("Crashing due to forced SBUG\n");
300 SBUG();
301 /* Unreachable */
302 } else {
303 *lenp = 0;
304 }
305
306 RETURN(0);
307 }
308
309 SPL_PROC_HANDLER(proc_console_max_delay_cs)
310 {
311 int rc, max_delay_cs;
312 struct ctl_table dummy = *table;
313 long d;
314 ENTRY;
315
316 dummy.data = &max_delay_cs;
317 dummy.proc_handler = &proc_dointvec;
318
319 if (write) {
320 max_delay_cs = 0;
321 rc = spl_proc_dointvec(&dummy,write,filp,buffer,lenp,ppos);
322 if (rc < 0)
323 RETURN(rc);
324
325 if (max_delay_cs <= 0)
326 RETURN(-EINVAL);
327
328 d = (max_delay_cs * HZ) / 100;
329 if (d == 0 || d < spl_console_min_delay)
330 RETURN(-EINVAL);
331
332 spl_console_max_delay = d;
333 } else {
334 max_delay_cs = (spl_console_max_delay * 100) / HZ;
335 rc = spl_proc_dointvec(&dummy,write,filp,buffer,lenp,ppos);
336 }
337
338 RETURN(rc);
339 }
340
341 SPL_PROC_HANDLER(proc_console_min_delay_cs)
342 {
343 int rc, min_delay_cs;
344 struct ctl_table dummy = *table;
345 long d;
346 ENTRY;
347
348 dummy.data = &min_delay_cs;
349 dummy.proc_handler = &proc_dointvec;
350
351 if (write) {
352 min_delay_cs = 0;
353 rc = spl_proc_dointvec(&dummy,write,filp,buffer,lenp,ppos);
354 if (rc < 0)
355 RETURN(rc);
356
357 if (min_delay_cs <= 0)
358 RETURN(-EINVAL);
359
360 d = (min_delay_cs * HZ) / 100;
361 if (d == 0 || d > spl_console_max_delay)
362 RETURN(-EINVAL);
363
364 spl_console_min_delay = d;
365 } else {
366 min_delay_cs = (spl_console_min_delay * 100) / HZ;
367 rc = spl_proc_dointvec(&dummy,write,filp,buffer,lenp,ppos);
368 }
369
370 RETURN(rc);
371 }
372
373 SPL_PROC_HANDLER(proc_console_backoff)
374 {
375 int rc, backoff;
376 struct ctl_table dummy = *table;
377 ENTRY;
378
379 dummy.data = &backoff;
380 dummy.proc_handler = &proc_dointvec;
381
382 if (write) {
383 backoff = 0;
384 rc = spl_proc_dointvec(&dummy,write,filp,buffer,lenp,ppos);
385 if (rc < 0)
386 RETURN(rc);
387
388 if (backoff <= 0)
389 RETURN(-EINVAL);
390
391 spl_console_backoff = backoff;
392 } else {
393 backoff = spl_console_backoff;
394 rc = spl_proc_dointvec(&dummy,write,filp,buffer,lenp,ppos);
395 }
396
397 RETURN(rc);
398 }
399
400 #ifdef DEBUG_KMEM
401 SPL_PROC_HANDLER(proc_domemused)
402 {
403 int rc = 0;
404 unsigned long min = 0, max = ~0, val;
405 struct ctl_table dummy = *table;
406 ENTRY;
407
408 dummy.data = &val;
409 dummy.proc_handler = &proc_dointvec;
410 dummy.extra1 = &min;
411 dummy.extra2 = &max;
412
413 if (write) {
414 *ppos += *lenp;
415 } else {
416 # ifdef HAVE_ATOMIC64_T
417 val = atomic64_read((atomic64_t *)table->data);
418 # else
419 val = atomic_read((atomic_t *)table->data);
420 # endif /* HAVE_ATOMIC64_T */
421 rc = spl_proc_doulongvec_minmax(&dummy, write, filp,
422 buffer, lenp, ppos);
423 }
424
425 RETURN(rc);
426 }
427 #endif /* DEBUG_KMEM */
428
429 SPL_PROC_HANDLER(proc_dohostid)
430 {
431 int len, rc = 0;
432 int32_t val;
433 char *end, str[32];
434 ENTRY;
435
436 if (write) {
437 /* We can't use spl_proc_doulongvec_minmax() in the write
438 * case hear because hostid while a hex value has no
439 * leading 0x which confuses the helper function. */
440 rc = proc_copyin_string(str, sizeof(str), buffer, *lenp);
441 if (rc < 0)
442 RETURN(rc);
443
444 val = simple_strtol(str, &end, 16);
445 if (str == end)
446 RETURN(-EINVAL);
447
448 spl_hostid = (long) val;
449 (void) snprintf(hw_serial, HW_HOSTID_LEN, "%u",
450 (val >= 0) ? val : -val);
451 hw_serial[HW_HOSTID_LEN - 1] = '\0';
452 *ppos += *lenp;
453 } else {
454 len = snprintf(str, sizeof(str), "%lx", spl_hostid);
455 if (*ppos >= len)
456 rc = 0;
457 else
458 rc = proc_copyout_string(buffer,*lenp,str+*ppos,"\n");
459
460 if (rc >= 0) {
461 *lenp = rc;
462 *ppos += rc;
463 }
464 }
465
466 RETURN(rc);
467 }
468
469 #ifndef HAVE_KALLSYMS_LOOKUP_NAME
470 SPL_PROC_HANDLER(proc_dokallsyms_lookup_name)
471 {
472 int len, rc = 0;
473 char *end, str[32];
474 ENTRY;
475
476 if (write) {
477 /* This may only be set once at module load time */
478 if (spl_kallsyms_lookup_name_fn != SYMBOL_POISON)
479 RETURN(-EEXIST);
480
481 /* We can't use spl_proc_doulongvec_minmax() in the write
482 * case hear because the address while a hex value has no
483 * leading 0x which confuses the helper function. */
484 rc = proc_copyin_string(str, sizeof(str), buffer, *lenp);
485 if (rc < 0)
486 RETURN(rc);
487
488 spl_kallsyms_lookup_name_fn =
489 (kallsyms_lookup_name_t)simple_strtoul(str, &end, 16);
490 if (str == end)
491 RETURN(-EINVAL);
492
493 *ppos += *lenp;
494 } else {
495 len = snprintf(str, sizeof(str), "%lx",
496 (unsigned long)spl_kallsyms_lookup_name_fn);
497 if (*ppos >= len)
498 rc = 0;
499 else
500 rc = proc_copyout_string(buffer,*lenp,str+*ppos,"\n");
501
502 if (rc >= 0) {
503 *lenp = rc;
504 *ppos += rc;
505 }
506 }
507
508 RETURN(rc);
509 }
510 #endif /* HAVE_KALLSYMS_LOOKUP_NAME */
511
512 SPL_PROC_HANDLER(proc_doavailrmem)
513 {
514 int len, rc = 0;
515 char str[32];
516 ENTRY;
517
518 if (write) {
519 *ppos += *lenp;
520 } else {
521 len = snprintf(str, sizeof(str), "%lu",
522 (unsigned long)availrmem);
523 if (*ppos >= len)
524 rc = 0;
525 else
526 rc = proc_copyout_string(buffer,*lenp,str+*ppos,"\n");
527
528 if (rc >= 0) {
529 *lenp = rc;
530 *ppos += rc;
531 }
532 }
533
534 RETURN(rc);
535 }
536
537 SPL_PROC_HANDLER(proc_dofreemem)
538 {
539 int len, rc = 0;
540 char str[32];
541 ENTRY;
542
543 if (write) {
544 *ppos += *lenp;
545 } else {
546 len = snprintf(str, sizeof(str), "%lu", (unsigned long)freemem);
547 if (*ppos >= len)
548 rc = 0;
549 else
550 rc = proc_copyout_string(buffer,*lenp,str+*ppos,"\n");
551
552 if (rc >= 0) {
553 *lenp = rc;
554 *ppos += rc;
555 }
556 }
557
558 RETURN(rc);
559 }
560
561 #ifdef DEBUG_KMEM
562 static void
563 slab_seq_show_headers(struct seq_file *f)
564 {
565 seq_printf(f, "%-36s %-6s - %s %s %s - %s %s %s - "
566 "%s %s %s - %s %s %s\n", "name", "flags",
567 "obj_size", "slab_objs", "slab_size",
568 "slab_fail", "slab_create", "slab_destroy",
569 "slab_total", "slab_alloc", "slab_max",
570 "obj_total", "obj_alloc", "obj_max");
571 }
572
573 static int
574 slab_seq_show(struct seq_file *f, void *p)
575 {
576 spl_kmem_cache_t *skc = p;
577
578 ASSERT(skc->skc_magic == SKC_MAGIC);
579
580 spin_lock(&skc->skc_lock);
581 seq_printf(f, "%-36s ", skc->skc_name);
582 seq_printf(f, "0x%04lx - %u %u %u - %lu %lu %lu - "
583 "%lu %lu %lu - %lu %lu %lu\n",
584 (long unsigned)skc->skc_flags,
585 (unsigned)skc->skc_obj_size,
586 (unsigned)skc->skc_slab_objs,
587 (unsigned)skc->skc_slab_size,
588 (long unsigned)skc->skc_slab_fail,
589 (long unsigned)skc->skc_slab_create,
590 (long unsigned)skc->skc_slab_destroy,
591 (long unsigned)skc->skc_slab_total,
592 (long unsigned)skc->skc_slab_alloc,
593 (long unsigned)skc->skc_slab_max,
594 (long unsigned)skc->skc_obj_total,
595 (long unsigned)skc->skc_obj_alloc,
596 (long unsigned)skc->skc_obj_max);
597
598 spin_unlock(&skc->skc_lock);
599
600 return 0;
601 }
602
603 static void *
604 slab_seq_start(struct seq_file *f, loff_t *pos)
605 {
606 struct list_head *p;
607 loff_t n = *pos;
608 ENTRY;
609
610 down_read(&spl_kmem_cache_sem);
611 if (!n)
612 slab_seq_show_headers(f);
613
614 p = spl_kmem_cache_list.next;
615 while (n--) {
616 p = p->next;
617 if (p == &spl_kmem_cache_list)
618 RETURN(NULL);
619 }
620
621 RETURN(list_entry(p, spl_kmem_cache_t, skc_list));
622 }
623
624 static void *
625 slab_seq_next(struct seq_file *f, void *p, loff_t *pos)
626 {
627 spl_kmem_cache_t *skc = p;
628 ENTRY;
629
630 ++*pos;
631 RETURN((skc->skc_list.next == &spl_kmem_cache_list) ?
632 NULL : list_entry(skc->skc_list.next,spl_kmem_cache_t,skc_list));
633 }
634
635 static void
636 slab_seq_stop(struct seq_file *f, void *v)
637 {
638 up_read(&spl_kmem_cache_sem);
639 }
640
641 static struct seq_operations slab_seq_ops = {
642 .show = slab_seq_show,
643 .start = slab_seq_start,
644 .next = slab_seq_next,
645 .stop = slab_seq_stop,
646 };
647
648 static int
649 proc_slab_open(struct inode *inode, struct file *filp)
650 {
651 return seq_open(filp, &slab_seq_ops);
652 }
653
654 static struct file_operations proc_slab_operations = {
655 .open = proc_slab_open,
656 .read = seq_read,
657 .llseek = seq_lseek,
658 .release = seq_release,
659 };
660 #endif /* DEBUG_KMEM */
661
662 static struct ctl_table spl_debug_table[] = {
663 {
664 .ctl_name = CTL_DEBUG_SUBSYS,
665 .procname = "subsystem",
666 .data = &spl_debug_subsys,
667 .maxlen = sizeof(unsigned long),
668 .mode = 0644,
669 .proc_handler = &proc_dobitmasks
670 },
671 {
672 .ctl_name = CTL_DEBUG_MASK,
673 .procname = "mask",
674 .data = &spl_debug_mask,
675 .maxlen = sizeof(unsigned long),
676 .mode = 0644,
677 .proc_handler = &proc_dobitmasks
678 },
679 {
680 .ctl_name = CTL_DEBUG_PRINTK,
681 .procname = "printk",
682 .data = &spl_debug_printk,
683 .maxlen = sizeof(unsigned long),
684 .mode = 0644,
685 .proc_handler = &proc_dobitmasks
686 },
687 {
688 .ctl_name = CTL_DEBUG_MB,
689 .procname = "mb",
690 .mode = 0644,
691 .proc_handler = &proc_debug_mb,
692 },
693 {
694 .ctl_name = CTL_DEBUG_BINARY,
695 .procname = "binary",
696 .data = &spl_debug_binary,
697 .maxlen = sizeof(int),
698 .mode = 0644,
699 .proc_handler = &proc_dointvec,
700 },
701 {
702 .ctl_name = CTL_DEBUG_CATASTROPHE,
703 .procname = "catastrophe",
704 .data = &spl_debug_catastrophe,
705 .maxlen = sizeof(int),
706 .mode = 0444,
707 .proc_handler = &proc_dointvec,
708 },
709 {
710 .ctl_name = CTL_DEBUG_PANIC_ON_BUG,
711 .procname = "panic_on_bug",
712 .data = &spl_debug_panic_on_bug,
713 .maxlen = sizeof(int),
714 .mode = 0644,
715 .proc_handler = &proc_dointvec
716 },
717 {
718 .ctl_name = CTL_DEBUG_PATH,
719 .procname = "path",
720 .data = spl_debug_file_path,
721 .maxlen = sizeof(spl_debug_file_path),
722 .mode = 0644,
723 .proc_handler = &proc_dostring,
724 },
725 {
726 .ctl_name = CTL_DEBUG_DUMP,
727 .procname = "dump",
728 .mode = 0200,
729 .proc_handler = &proc_dump_kernel,
730 },
731 { .ctl_name = CTL_DEBUG_FORCE_BUG,
732 .procname = "force_bug",
733 .mode = 0200,
734 .proc_handler = &proc_force_bug,
735 },
736 {
737 .ctl_name = CTL_CONSOLE_RATELIMIT,
738 .procname = "console_ratelimit",
739 .data = &spl_console_ratelimit,
740 .maxlen = sizeof(int),
741 .mode = 0644,
742 .proc_handler = &proc_dointvec,
743 },
744 {
745 .ctl_name = CTL_CONSOLE_MAX_DELAY_CS,
746 .procname = "console_max_delay_centisecs",
747 .maxlen = sizeof(int),
748 .mode = 0644,
749 .proc_handler = &proc_console_max_delay_cs,
750 },
751 {
752 .ctl_name = CTL_CONSOLE_MIN_DELAY_CS,
753 .procname = "console_min_delay_centisecs",
754 .maxlen = sizeof(int),
755 .mode = 0644,
756 .proc_handler = &proc_console_min_delay_cs,
757 },
758 {
759 .ctl_name = CTL_CONSOLE_BACKOFF,
760 .procname = "console_backoff",
761 .maxlen = sizeof(int),
762 .mode = 0644,
763 .proc_handler = &proc_console_backoff,
764 },
765 {
766 .ctl_name = CTL_DEBUG_STACK_SIZE,
767 .procname = "stack_max",
768 .data = &spl_debug_stack,
769 .maxlen = sizeof(int),
770 .mode = 0444,
771 .proc_handler = &proc_dointvec,
772 },
773 {0},
774 };
775
776 static struct ctl_table spl_vm_table[] = {
777 {
778 .ctl_name = CTL_VM_MINFREE,
779 .procname = "minfree",
780 .data = &minfree,
781 .maxlen = sizeof(int),
782 .mode = 0644,
783 .proc_handler = &proc_dointvec,
784 },
785 {
786 .ctl_name = CTL_VM_DESFREE,
787 .procname = "desfree",
788 .data = &desfree,
789 .maxlen = sizeof(int),
790 .mode = 0644,
791 .proc_handler = &proc_dointvec,
792 },
793 {
794 .ctl_name = CTL_VM_LOTSFREE,
795 .procname = "lotsfree",
796 .data = &lotsfree,
797 .maxlen = sizeof(int),
798 .mode = 0644,
799 .proc_handler = &proc_dointvec,
800 },
801 {
802 .ctl_name = CTL_VM_NEEDFREE,
803 .procname = "needfree",
804 .data = &needfree,
805 .maxlen = sizeof(int),
806 .mode = 0444,
807 .proc_handler = &proc_dointvec,
808 },
809 {
810 .ctl_name = CTL_VM_SWAPFS_MINFREE,
811 .procname = "swapfs_minfree",
812 .data = &swapfs_minfree,
813 .maxlen = sizeof(int),
814 .mode = 0644,
815 .proc_handler = &proc_dointvec,
816 },
817 {
818 .ctl_name = CTL_VM_SWAPFS_RESERVE,
819 .procname = "swapfs_reserve",
820 .data = &swapfs_reserve,
821 .maxlen = sizeof(int),
822 .mode = 0644,
823 .proc_handler = &proc_dointvec,
824 },
825 {
826 .ctl_name = CTL_VM_AVAILRMEM,
827 .procname = "availrmem",
828 .mode = 0444,
829 .proc_handler = &proc_doavailrmem,
830 },
831 {
832 .ctl_name = CTL_VM_FREEMEM,
833 .procname = "freemem",
834 .data = (void *)2,
835 .maxlen = sizeof(int),
836 .mode = 0444,
837 .proc_handler = &proc_dofreemem,
838 },
839 {
840 .ctl_name = CTL_VM_PHYSMEM,
841 .procname = "physmem",
842 .data = &physmem,
843 .maxlen = sizeof(int),
844 .mode = 0444,
845 .proc_handler = &proc_dointvec,
846 },
847 {0},
848 };
849
850 #ifdef DEBUG_KMEM
851 static struct ctl_table spl_kmem_table[] = {
852 {
853 .ctl_name = CTL_KMEM_KMEMUSED,
854 .procname = "kmem_used",
855 .data = &kmem_alloc_used,
856 # ifdef HAVE_ATOMIC64_T
857 .maxlen = sizeof(atomic64_t),
858 # else
859 .maxlen = sizeof(atomic_t),
860 # endif /* HAVE_ATOMIC64_T */
861 .mode = 0444,
862 .proc_handler = &proc_domemused,
863 },
864 {
865 .ctl_name = CTL_KMEM_KMEMMAX,
866 .procname = "kmem_max",
867 .data = &kmem_alloc_max,
868 .maxlen = sizeof(unsigned long),
869 .extra1 = &table_min,
870 .extra2 = &table_max,
871 .mode = 0444,
872 .proc_handler = &proc_doulongvec_minmax,
873 },
874 {
875 .ctl_name = CTL_KMEM_VMEMUSED,
876 .procname = "vmem_used",
877 .data = &vmem_alloc_used,
878 # ifdef HAVE_ATOMIC64_T
879 .maxlen = sizeof(atomic64_t),
880 # else
881 .maxlen = sizeof(atomic_t),
882 # endif /* HAVE_ATOMIC64_T */
883 .mode = 0444,
884 .proc_handler = &proc_domemused,
885 },
886 {
887 .ctl_name = CTL_KMEM_VMEMMAX,
888 .procname = "vmem_max",
889 .data = &vmem_alloc_max,
890 .maxlen = sizeof(unsigned long),
891 .extra1 = &table_min,
892 .extra2 = &table_max,
893 .mode = 0444,
894 .proc_handler = &proc_doulongvec_minmax,
895 },
896 {0},
897 };
898 #endif /* DEBUG_KMEM */
899
900 static struct ctl_table spl_kstat_table[] = {
901 {0},
902 };
903
904 static struct ctl_table spl_table[] = {
905 /* NB No .strategy entries have been provided since
906 * sysctl(8) prefers to go via /proc for portability.
907 */
908 {
909 .ctl_name = CTL_VERSION,
910 .procname = "version",
911 .data = spl_version,
912 .maxlen = sizeof(spl_version),
913 .mode = 0444,
914 .proc_handler = &proc_dostring,
915 },
916 {
917 .ctl_name = CTL_HOSTID,
918 .procname = "hostid",
919 .data = &spl_hostid,
920 .maxlen = sizeof(unsigned long),
921 .mode = 0644,
922 .proc_handler = &proc_dohostid,
923 },
924 {
925 .ctl_name = CTL_HW_SERIAL,
926 .procname = "hw_serial",
927 .data = hw_serial,
928 .maxlen = sizeof(hw_serial),
929 .mode = 0444,
930 .proc_handler = &proc_dostring,
931 },
932 #ifndef HAVE_KALLSYMS_LOOKUP_NAME
933 {
934 .ctl_name = CTL_KALLSYMS,
935 .procname = "kallsyms_lookup_name",
936 .data = &spl_kallsyms_lookup_name_fn,
937 .maxlen = sizeof(unsigned long),
938 .mode = 0644,
939 .proc_handler = &proc_dokallsyms_lookup_name,
940 },
941 #endif
942 {
943 .ctl_name = CTL_SPL_DEBUG,
944 .procname = "debug",
945 .mode = 0555,
946 .child = spl_debug_table,
947 },
948 {
949 .ctl_name = CTL_SPL_VM,
950 .procname = "vm",
951 .mode = 0555,
952 .child = spl_vm_table,
953 },
954 #ifdef DEBUG_KMEM
955 {
956 .ctl_name = CTL_SPL_KMEM,
957 .procname = "kmem",
958 .mode = 0555,
959 .child = spl_kmem_table,
960 },
961 #endif
962 {
963 .ctl_name = CTL_SPL_KSTAT,
964 .procname = "kstat",
965 .mode = 0555,
966 .child = spl_kstat_table,
967 },
968 { 0 },
969 };
970
971 static struct ctl_table spl_dir[] = {
972 {
973 .ctl_name = CTL_SPL,
974 .procname = "spl",
975 .mode = 0555,
976 .child = spl_table,
977 },
978 { 0 }
979 };
980
981 static struct ctl_table spl_root[] = {
982 {
983 .ctl_name = CTL_KERN,
984 .procname = "kernel",
985 .mode = 0555,
986 .child = spl_dir,
987 },
988 { 0 }
989 };
990
991 static int
992 proc_dir_entry_match(int len, const char *name, struct proc_dir_entry *de)
993 {
994 if (de->namelen != len)
995 return 0;
996
997 return !memcmp(name, de->name, len);
998 }
999
1000 struct proc_dir_entry *
1001 proc_dir_entry_find(struct proc_dir_entry *root, const char *str)
1002 {
1003 struct proc_dir_entry *de;
1004
1005 for (de = root->subdir; de; de = de->next)
1006 if (proc_dir_entry_match(strlen(str), str, de))
1007 return de;
1008
1009 return NULL;
1010 }
1011
1012 int
1013 proc_dir_entries(struct proc_dir_entry *root)
1014 {
1015 struct proc_dir_entry *de;
1016 int i = 0;
1017
1018 for (de = root->subdir; de; de = de->next)
1019 i++;
1020
1021 return i;
1022 }
1023
1024 int
1025 proc_init(void)
1026 {
1027 int rc = 0;
1028 ENTRY;
1029
1030 #ifdef CONFIG_SYSCTL
1031 spl_header = spl_register_sysctl_table(spl_root, 0);
1032 if (spl_header == NULL)
1033 RETURN(-EUNATCH);
1034 #endif /* CONFIG_SYSCTL */
1035
1036 proc_spl = proc_mkdir("spl", NULL);
1037 if (proc_spl == NULL)
1038 GOTO(out, rc = -EUNATCH);
1039
1040 #ifdef DEBUG_KMEM
1041 proc_spl_kmem = proc_mkdir("kmem", proc_spl);
1042 if (proc_spl_kmem == NULL)
1043 GOTO(out, rc = -EUNATCH);
1044
1045 proc_spl_kmem_slab = create_proc_entry("slab", 0444, proc_spl_kmem);
1046 if (proc_spl_kmem_slab == NULL)
1047 GOTO(out, rc = -EUNATCH);
1048
1049 proc_spl_kmem_slab->proc_fops = &proc_slab_operations;
1050 #endif /* DEBUG_KMEM */
1051
1052 proc_spl_kstat = proc_mkdir("kstat", proc_spl);
1053 if (proc_spl_kstat == NULL)
1054 GOTO(out, rc = -EUNATCH);
1055 out:
1056 if (rc) {
1057 remove_proc_entry("kstat", proc_spl);
1058 #ifdef DEBUG_KMEM
1059 remove_proc_entry("slab", proc_spl_kmem);
1060 remove_proc_entry("kmem", proc_spl);
1061 #endif
1062 remove_proc_entry("spl", NULL);
1063 #ifdef CONFIG_SYSCTL
1064 spl_unregister_sysctl_table(spl_header);
1065 #endif /* CONFIG_SYSCTL */
1066 }
1067
1068 RETURN(rc);
1069 }
1070
1071 void
1072 proc_fini(void)
1073 {
1074 ENTRY;
1075
1076 remove_proc_entry("kstat", proc_spl);
1077 #ifdef DEBUG_KMEM
1078 remove_proc_entry("slab", proc_spl_kmem);
1079 remove_proc_entry("kmem", proc_spl);
1080 #endif
1081 remove_proc_entry("spl", NULL);
1082
1083 #ifdef CONFIG_SYSCTL
1084 ASSERT(spl_header != NULL);
1085 spl_unregister_sysctl_table(spl_header);
1086 #endif /* CONFIG_SYSCTL */
1087
1088 EXIT;
1089 }