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