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>.
8 * This file is part of the SPL, Solaris Porting Layer.
9 * For details, see <http://zfsonlinux.org/>.
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.
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
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 \*****************************************************************************/
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>
35 #ifdef SS_DEBUG_SUBSYS
36 #undef SS_DEBUG_SUBSYS
39 #define SS_DEBUG_SUBSYS SS_PROC
41 #if defined(CONSTIFY_PLUGIN) && LINUX_VERSION_CODE >= KERNEL_VERSION(3,8,0)
42 typedef struct ctl_table __no_const spl_ctl_table
;
44 typedef struct ctl_table spl_ctl_table
;
48 static unsigned long table_min
= 0;
49 static unsigned long table_max
= ~0;
52 static struct ctl_table_header
*spl_header
= NULL
;
53 static struct proc_dir_entry
*proc_spl
= NULL
;
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
;
61 proc_copyin_string(char *kbuffer
, int kbuffer_size
,
62 const char *ubuffer
, int ubuffer_size
)
66 if (ubuffer_size
> kbuffer_size
)
69 if (copy_from_user((void *)kbuffer
, (void *)ubuffer
, ubuffer_size
))
72 /* strip trailing whitespace */
73 size
= strnlen(kbuffer
, ubuffer_size
);
75 if (!isspace(kbuffer
[size
]))
82 /* no space to terminate */
83 if (size
== kbuffer_size
)
86 kbuffer
[size
+ 1] = 0;
91 proc_copyout_string(char *ubuffer
, int ubuffer_size
,
92 const char *kbuffer
, char *append
)
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
98 int size
= MIN(strlen(kbuffer
), ubuffer_size
);
100 if (copy_to_user(ubuffer
, kbuffer
, size
))
103 if (append
!= NULL
&& size
< ubuffer_size
) {
104 if (copy_to_user(ubuffer
+ size
, append
, 1))
115 proc_dobitmasks(struct ctl_table
*table
, int write
,
116 void __user
*buffer
, size_t *lenp
, loff_t
*ppos
)
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;
125 str
= kmem_alloc(size
, KM_SLEEP
);
130 rc
= proc_copyin_string(str
, size
, buffer
, *lenp
);
134 rc
= spl_debug_str2mask(mask
, str
, is_subsys
);
135 /* Always print BUG/ASSERT to console, so keep this mask */
141 rc
= spl_debug_mask2str(str
, size
, *mask
, is_subsys
);
145 rc
= proc_copyout_string(buffer
, *lenp
,
153 kmem_free(str
, size
);
158 proc_debug_mb(struct ctl_table
*table
, int write
,
159 void __user
*buffer
, size_t *lenp
, loff_t
*ppos
)
166 rc
= proc_copyin_string(str
, sizeof(str
), buffer
, *lenp
);
170 rc
= spl_debug_set_mb(simple_strtoul(str
, NULL
, 0));
173 len
= snprintf(str
, sizeof(str
), "%d", spl_debug_get_mb());
177 rc
= proc_copyout_string(buffer
,*lenp
,str
+*ppos
,"\n");
189 proc_dump_kernel(struct ctl_table
*table
, int write
,
190 void __user
*buffer
, size_t *lenp
, loff_t
*ppos
)
195 spl_debug_dumplog(0);
205 proc_force_bug(struct ctl_table
*table
, int write
,
206 void __user
*buffer
, size_t *lenp
, loff_t
*ppos
)
211 PANIC("Crashing due to forced panic\n");
219 proc_console_max_delay_cs(struct ctl_table
*table
, int write
,
220 void __user
*buffer
, size_t *lenp
, loff_t
*ppos
)
222 int rc
, max_delay_cs
;
223 spl_ctl_table dummy
= *table
;
227 dummy
.data
= &max_delay_cs
;
228 dummy
.proc_handler
= &proc_dointvec
;
232 rc
= proc_dointvec(&dummy
, write
, buffer
, lenp
, ppos
);
236 if (max_delay_cs
<= 0)
239 d
= (max_delay_cs
* HZ
) / 100;
240 if (d
== 0 || d
< spl_console_min_delay
)
243 spl_console_max_delay
= d
;
245 max_delay_cs
= (spl_console_max_delay
* 100) / HZ
;
246 rc
= proc_dointvec(&dummy
, write
, buffer
, lenp
, ppos
);
253 proc_console_min_delay_cs(struct ctl_table
*table
, int write
,
254 void __user
*buffer
, size_t *lenp
, loff_t
*ppos
)
256 int rc
, min_delay_cs
;
257 spl_ctl_table dummy
= *table
;
261 dummy
.data
= &min_delay_cs
;
262 dummy
.proc_handler
= &proc_dointvec
;
266 rc
= proc_dointvec(&dummy
, write
, buffer
, lenp
, ppos
);
270 if (min_delay_cs
<= 0)
273 d
= (min_delay_cs
* HZ
) / 100;
274 if (d
== 0 || d
> spl_console_max_delay
)
277 spl_console_min_delay
= d
;
279 min_delay_cs
= (spl_console_min_delay
* 100) / HZ
;
280 rc
= proc_dointvec(&dummy
, write
, buffer
, lenp
, ppos
);
287 proc_console_backoff(struct ctl_table
*table
, int write
,
288 void __user
*buffer
, size_t *lenp
, loff_t
*ppos
)
291 spl_ctl_table dummy
= *table
;
294 dummy
.data
= &backoff
;
295 dummy
.proc_handler
= &proc_dointvec
;
299 rc
= proc_dointvec(&dummy
, write
, buffer
, lenp
, ppos
);
306 spl_console_backoff
= backoff
;
308 backoff
= spl_console_backoff
;
309 rc
= proc_dointvec(&dummy
, write
, buffer
, lenp
, ppos
);
314 #endif /* DEBUG_LOG */
318 proc_domemused(struct ctl_table
*table
, int write
,
319 void __user
*buffer
, size_t *lenp
, loff_t
*ppos
)
322 unsigned long min
= 0, max
= ~0, val
;
323 spl_ctl_table dummy
= *table
;
327 dummy
.proc_handler
= &proc_dointvec
;
334 # ifdef HAVE_ATOMIC64_T
335 val
= atomic64_read((atomic64_t
*)table
->data
);
337 val
= atomic_read((atomic_t
*)table
->data
);
338 # endif /* HAVE_ATOMIC64_T */
339 rc
= proc_doulongvec_minmax(&dummy
, write
, buffer
, lenp
, ppos
);
346 proc_doslab(struct ctl_table
*table
, int write
,
347 void __user
*buffer
, size_t *lenp
, loff_t
*ppos
)
350 unsigned long min
= 0, max
= ~0, val
= 0, mask
;
351 spl_ctl_table dummy
= *table
;
352 spl_kmem_cache_t
*skc
;
356 dummy
.proc_handler
= &proc_dointvec
;
363 down_read(&spl_kmem_cache_sem
);
364 mask
= (unsigned long)table
->data
;
366 list_for_each_entry(skc
, &spl_kmem_cache_list
, skc_list
) {
368 /* Only use slabs of the correct kmem/vmem type */
369 if (!(skc
->skc_flags
& mask
))
372 /* Sum the specified field for selected slabs */
373 switch (mask
& (KMC_TOTAL
| KMC_ALLOC
| KMC_MAX
)) {
375 val
+= skc
->skc_slab_size
* skc
->skc_slab_total
;
378 val
+= skc
->skc_obj_size
* skc
->skc_obj_alloc
;
381 val
+= skc
->skc_obj_size
* skc
->skc_obj_max
;
386 up_read(&spl_kmem_cache_sem
);
387 rc
= proc_doulongvec_minmax(&dummy
, write
, buffer
, lenp
, ppos
);
392 #endif /* DEBUG_KMEM */
395 proc_dohostid(struct ctl_table
*table
, int write
,
396 void __user
*buffer
, size_t *lenp
, loff_t
*ppos
)
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
);
410 spl_hostid
= simple_strtoul(str
, &end
, 16);
415 len
= snprintf(str
, sizeof(str
), "%lx", spl_hostid
);
419 rc
= proc_copyout_string(buffer
,*lenp
,str
+*ppos
,"\n");
432 slab_seq_show_headers(struct seq_file
*f
)
435 "--------------------- cache ----------"
436 "--------------------------------------------- "
439 "--- emergency ---\n");
442 " flags size alloc slabsize objsize "
445 "dlock alloc max\n");
449 slab_seq_show(struct seq_file
*f
, void *p
)
451 spl_kmem_cache_t
*skc
= p
;
453 ASSERT(skc
->skc_magic
== SKC_MAGIC
);
456 * Backed by Linux slab see /proc/slabinfo.
458 if (skc
->skc_flags
& KMC_SLAB
)
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
);
480 spin_unlock(&skc
->skc_lock
);
486 slab_seq_start(struct seq_file
*f
, loff_t
*pos
)
492 down_read(&spl_kmem_cache_sem
);
494 slab_seq_show_headers(f
);
496 p
= spl_kmem_cache_list
.next
;
499 if (p
== &spl_kmem_cache_list
)
503 SRETURN(list_entry(p
, spl_kmem_cache_t
, skc_list
));
507 slab_seq_next(struct seq_file
*f
, void *p
, loff_t
*pos
)
509 spl_kmem_cache_t
*skc
= p
;
513 SRETURN((skc
->skc_list
.next
== &spl_kmem_cache_list
) ?
514 NULL
: list_entry(skc
->skc_list
.next
,spl_kmem_cache_t
,skc_list
));
518 slab_seq_stop(struct seq_file
*f
, void *v
)
520 up_read(&spl_kmem_cache_sem
);
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
,
531 proc_slab_open(struct inode
*inode
, struct file
*filp
)
533 return seq_open(filp
, &slab_seq_ops
);
536 static struct file_operations proc_slab_operations
= {
537 .open
= proc_slab_open
,
540 .release
= seq_release
,
542 #endif /* DEBUG_KMEM */
545 static struct ctl_table spl_debug_table
[] = {
547 .procname
= "subsystem",
548 .data
= &spl_debug_subsys
,
549 .maxlen
= sizeof(unsigned long),
551 .proc_handler
= &proc_dobitmasks
555 .data
= &spl_debug_mask
,
556 .maxlen
= sizeof(unsigned long),
558 .proc_handler
= &proc_dobitmasks
561 .procname
= "printk",
562 .data
= &spl_debug_printk
,
563 .maxlen
= sizeof(unsigned long),
565 .proc_handler
= &proc_dobitmasks
570 .proc_handler
= &proc_debug_mb
,
573 .procname
= "binary",
574 .data
= &spl_debug_binary
,
575 .maxlen
= sizeof(int),
577 .proc_handler
= &proc_dointvec
,
580 .procname
= "catastrophe",
581 .data
= &spl_debug_catastrophe
,
582 .maxlen
= sizeof(int),
584 .proc_handler
= &proc_dointvec
,
587 .procname
= "panic_on_bug",
588 .data
= &spl_debug_panic_on_bug
,
589 .maxlen
= sizeof(int),
591 .proc_handler
= &proc_dointvec
595 .data
= spl_debug_file_path
,
596 .maxlen
= sizeof(spl_debug_file_path
),
598 .proc_handler
= &proc_dostring
,
603 .proc_handler
= &proc_dump_kernel
,
606 .procname
= "force_bug",
608 .proc_handler
= &proc_force_bug
,
611 .procname
= "console_ratelimit",
612 .data
= &spl_console_ratelimit
,
613 .maxlen
= sizeof(int),
615 .proc_handler
= &proc_dointvec
,
618 .procname
= "console_max_delay_centisecs",
619 .maxlen
= sizeof(int),
621 .proc_handler
= &proc_console_max_delay_cs
,
624 .procname
= "console_min_delay_centisecs",
625 .maxlen
= sizeof(int),
627 .proc_handler
= &proc_console_min_delay_cs
,
630 .procname
= "console_backoff",
631 .maxlen
= sizeof(int),
633 .proc_handler
= &proc_console_backoff
,
636 .procname
= "stack_max",
637 .data
= &spl_debug_stack
,
638 .maxlen
= sizeof(int),
640 .proc_handler
= &proc_dointvec
,
644 #endif /* DEBUG_LOG */
647 static struct ctl_table spl_kmem_table
[] = {
649 .procname
= "kmem_used",
650 .data
= &kmem_alloc_used
,
651 # ifdef HAVE_ATOMIC64_T
652 .maxlen
= sizeof(atomic64_t
),
654 .maxlen
= sizeof(atomic_t
),
655 # endif /* HAVE_ATOMIC64_T */
657 .proc_handler
= &proc_domemused
,
660 .procname
= "kmem_max",
661 .data
= &kmem_alloc_max
,
662 .maxlen
= sizeof(unsigned long),
663 .extra1
= &table_min
,
664 .extra2
= &table_max
,
666 .proc_handler
= &proc_doulongvec_minmax
,
669 .procname
= "vmem_used",
670 .data
= &vmem_alloc_used
,
671 # ifdef HAVE_ATOMIC64_T
672 .maxlen
= sizeof(atomic64_t
),
674 .maxlen
= sizeof(atomic_t
),
675 # endif /* HAVE_ATOMIC64_T */
677 .proc_handler
= &proc_domemused
,
680 .procname
= "vmem_max",
681 .data
= &vmem_alloc_max
,
682 .maxlen
= sizeof(unsigned long),
683 .extra1
= &table_min
,
684 .extra2
= &table_max
,
686 .proc_handler
= &proc_doulongvec_minmax
,
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
,
695 .proc_handler
= &proc_doslab
,
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
,
704 .proc_handler
= &proc_doslab
,
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
,
713 .proc_handler
= &proc_doslab
,
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
,
722 .proc_handler
= &proc_doslab
,
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
,
731 .proc_handler
= &proc_doslab
,
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
,
740 .proc_handler
= &proc_doslab
,
744 #endif /* DEBUG_KMEM */
746 static struct ctl_table spl_kstat_table
[] = {
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.
755 .procname
= "version",
757 .maxlen
= sizeof(spl_version
),
759 .proc_handler
= &proc_dostring
,
762 .procname
= "hostid",
764 .maxlen
= sizeof(unsigned long),
766 .proc_handler
= &proc_dohostid
,
772 .child
= spl_debug_table
,
779 .child
= spl_kmem_table
,
785 .child
= spl_kstat_table
,
790 static struct ctl_table spl_dir
[] = {
799 static struct ctl_table spl_root
[] = {
802 .ctl_name
= CTL_KERN
,
804 .procname
= "kernel",
817 spl_header
= register_sysctl_table(spl_root
);
818 if (spl_header
== NULL
)
821 proc_spl
= proc_mkdir("spl", NULL
);
822 if (proc_spl
== NULL
)
823 SGOTO(out
, rc
= -EUNATCH
);
826 proc_spl_kmem
= proc_mkdir("kmem", proc_spl
);
827 if (proc_spl_kmem
== NULL
)
828 SGOTO(out
, rc
= -EUNATCH
);
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
);
835 #endif /* DEBUG_KMEM */
837 proc_spl_kstat
= proc_mkdir("kstat", proc_spl
);
838 if (proc_spl_kstat
== NULL
)
839 SGOTO(out
, rc
= -EUNATCH
);
842 remove_proc_entry("kstat", proc_spl
);
844 remove_proc_entry("slab", proc_spl_kmem
);
845 remove_proc_entry("kmem", proc_spl
);
847 remove_proc_entry("spl", NULL
);
848 unregister_sysctl_table(spl_header
);
859 remove_proc_entry("kstat", proc_spl
);
861 remove_proc_entry("slab", proc_spl_kmem
);
862 remove_proc_entry("kmem", proc_spl
);
864 remove_proc_entry("spl", NULL
);
866 ASSERT(spl_header
!= NULL
);
867 unregister_sysctl_table(spl_header
);