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/>.
24 * Solaris Porting Layer (SPL) Proc Implementation.
27 #include <sys/systeminfo.h>
28 #include <sys/kstat.h>
30 #include <sys/kmem_cache.h>
32 #include <sys/taskq.h>
33 #include <linux/ctype.h>
34 #include <linux/kmod.h>
35 #include <linux/seq_file.h>
36 #include <linux/proc_compat.h>
37 #include <linux/uaccess.h>
38 #include <linux/version.h>
40 #if defined(CONSTIFY_PLUGIN) && LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
41 typedef struct ctl_table __no_const spl_ctl_table
;
43 typedef struct ctl_table spl_ctl_table
;
46 static unsigned long table_min
= 0;
47 static unsigned long table_max
= ~0;
49 static struct ctl_table_header
*spl_header
= NULL
;
50 static struct proc_dir_entry
*proc_spl
= NULL
;
51 static struct proc_dir_entry
*proc_spl_kmem
= NULL
;
52 static struct proc_dir_entry
*proc_spl_kmem_slab
= NULL
;
53 static struct proc_dir_entry
*proc_spl_taskq_all
= NULL
;
54 static struct proc_dir_entry
*proc_spl_taskq
= NULL
;
55 struct proc_dir_entry
*proc_spl_kstat
= NULL
;
58 proc_copyin_string(char *kbuffer
, int kbuffer_size
, const char *ubuffer
,
63 if (ubuffer_size
> kbuffer_size
)
66 if (copy_from_user((void *)kbuffer
, (void *)ubuffer
, ubuffer_size
))
69 /* strip trailing whitespace */
70 size
= strnlen(kbuffer
, ubuffer_size
);
72 if (!isspace(kbuffer
[size
]))
79 /* no space to terminate */
80 if (size
== kbuffer_size
)
83 kbuffer
[size
+ 1] = 0;
88 proc_copyout_string(char *ubuffer
, int ubuffer_size
,
89 const char *kbuffer
, char *append
)
92 * NB if 'append' != NULL, it's a single character to append to the
93 * copied out string - usually "\n", for /proc entries and
94 * (i.e. a terminating zero byte) for sysctl entries
96 int size
= MIN(strlen(kbuffer
), ubuffer_size
);
98 if (copy_to_user(ubuffer
, kbuffer
, size
))
101 if (append
!= NULL
&& size
< ubuffer_size
) {
102 if (copy_to_user(ubuffer
+ size
, append
, 1))
113 proc_domemused(struct ctl_table
*table
, int write
,
114 void __user
*buffer
, size_t *lenp
, loff_t
*ppos
)
117 unsigned long min
= 0, max
= ~0, val
;
118 spl_ctl_table dummy
= *table
;
121 dummy
.proc_handler
= &proc_dointvec
;
128 #ifdef HAVE_ATOMIC64_T
129 val
= atomic64_read((atomic64_t
*)table
->data
);
131 val
= atomic_read((atomic_t
*)table
->data
);
132 #endif /* HAVE_ATOMIC64_T */
133 rc
= proc_doulongvec_minmax(&dummy
, write
, buffer
, lenp
, ppos
);
138 #endif /* DEBUG_KMEM */
141 proc_doslab(struct ctl_table
*table
, int write
,
142 void __user
*buffer
, size_t *lenp
, loff_t
*ppos
)
145 unsigned long min
= 0, max
= ~0, val
= 0, mask
;
146 spl_ctl_table dummy
= *table
;
147 spl_kmem_cache_t
*skc
;
150 dummy
.proc_handler
= &proc_dointvec
;
157 down_read(&spl_kmem_cache_sem
);
158 mask
= (unsigned long)table
->data
;
160 list_for_each_entry(skc
, &spl_kmem_cache_list
, skc_list
) {
162 /* Only use slabs of the correct kmem/vmem type */
163 if (!(skc
->skc_flags
& mask
))
166 /* Sum the specified field for selected slabs */
167 switch (mask
& (KMC_TOTAL
| KMC_ALLOC
| KMC_MAX
)) {
169 val
+= skc
->skc_slab_size
* skc
->skc_slab_total
;
172 val
+= skc
->skc_obj_size
* skc
->skc_obj_alloc
;
175 val
+= skc
->skc_obj_size
* skc
->skc_obj_max
;
180 up_read(&spl_kmem_cache_sem
);
181 rc
= proc_doulongvec_minmax(&dummy
, write
, buffer
, lenp
, ppos
);
188 proc_dohostid(struct ctl_table
*table
, int write
,
189 void __user
*buffer
, size_t *lenp
, loff_t
*ppos
)
196 * We can't use proc_doulongvec_minmax() in the write
197 * case here because hostid while a hex value has no
198 * leading 0x which confuses the helper function.
200 rc
= proc_copyin_string(str
, sizeof (str
), buffer
, *lenp
);
204 spl_hostid
= simple_strtoul(str
, &end
, 16);
209 len
= snprintf(str
, sizeof (str
), "%lx",
210 (unsigned long) zone_get_hostid(NULL
));
214 rc
= proc_copyout_string(buffer
,
215 *lenp
, str
+ *ppos
, "\n");
227 taskq_seq_show_headers(struct seq_file
*f
)
229 seq_printf(f
, "%-25s %5s %5s %5s %5s %5s %5s %12s %5s %10s\n",
230 "taskq", "act", "nthr", "spwn", "maxt", "pri",
231 "mina", "maxa", "cura", "flags");
234 /* indices into the lheads array below */
237 #define LHEAD_DELAY 2
239 #define LHEAD_ACTIVE 4
242 static unsigned int spl_max_show_tasks
= 512;
243 module_param(spl_max_show_tasks
, uint
, 0644);
244 MODULE_PARM_DESC(spl_max_show_tasks
, "Max number of tasks shown in taskq proc");
247 taskq_seq_show_impl(struct seq_file
*f
, void *p
, boolean_t allflag
)
251 spl_wait_queue_entry_t
*wq
;
252 struct task_struct
*tsk
;
255 struct list_head
*lheads
[LHEAD_SIZE
], *lh
;
256 static char *list_names
[LHEAD_SIZE
] =
257 {"pend", "prio", "delay", "wait", "active" };
258 int i
, j
, have_lheads
= 0;
259 unsigned long wflags
, flags
;
261 spin_lock_irqsave_nested(&tq
->tq_lock
, flags
, tq
->tq_lock_class
);
262 spin_lock_irqsave(&tq
->tq_wait_waitq
.lock
, wflags
);
264 /* get the various lists and check whether they're empty */
265 lheads
[LHEAD_PEND
] = &tq
->tq_pend_list
;
266 lheads
[LHEAD_PRIO
] = &tq
->tq_prio_list
;
267 lheads
[LHEAD_DELAY
] = &tq
->tq_delay_list
;
268 #ifdef HAVE_WAIT_QUEUE_HEAD_ENTRY
269 lheads
[LHEAD_WAIT
] = &tq
->tq_wait_waitq
.head
;
271 lheads
[LHEAD_WAIT
] = &tq
->tq_wait_waitq
.task_list
;
273 lheads
[LHEAD_ACTIVE
] = &tq
->tq_active_list
;
275 for (i
= 0; i
< LHEAD_SIZE
; ++i
) {
276 if (list_empty(lheads
[i
]))
282 /* early return in non-"all" mode if lists are all empty */
283 if (!allflag
&& !have_lheads
) {
284 spin_unlock_irqrestore(&tq
->tq_wait_waitq
.lock
, wflags
);
285 spin_unlock_irqrestore(&tq
->tq_lock
, flags
);
289 /* unlock the waitq quickly */
290 if (!lheads
[LHEAD_WAIT
])
291 spin_unlock_irqrestore(&tq
->tq_wait_waitq
.lock
, wflags
);
293 /* show the base taskq contents */
294 snprintf(name
, sizeof (name
), "%s/%d", tq
->tq_name
, tq
->tq_instance
);
295 seq_printf(f
, "%-25s ", name
);
296 seq_printf(f
, "%5d %5d %5d %5d %5d %5d %12d %5d %10x\n",
297 tq
->tq_nactive
, tq
->tq_nthreads
, tq
->tq_nspawn
,
298 tq
->tq_maxthreads
, tq
->tq_pri
, tq
->tq_minalloc
, tq
->tq_maxalloc
,
299 tq
->tq_nalloc
, tq
->tq_flags
);
301 /* show the active list */
302 if (lheads
[LHEAD_ACTIVE
]) {
304 list_for_each_entry(tqt
, &tq
->tq_active_list
, tqt_active_list
) {
306 seq_printf(f
, "\t%s:",
307 list_names
[LHEAD_ACTIVE
]);
309 seq_printf(f
, "\n\t ");
312 seq_printf(f
, " [%d]%pf(%ps)",
313 tqt
->tqt_thread
->pid
,
314 tqt
->tqt_task
->tqent_func
,
315 tqt
->tqt_task
->tqent_arg
);
321 for (i
= LHEAD_PEND
; i
<= LHEAD_WAIT
; ++i
)
324 list_for_each(lh
, lheads
[i
]) {
325 if (spl_max_show_tasks
!= 0 &&
326 j
>= spl_max_show_tasks
) {
327 seq_printf(f
, "\n\t(truncated)");
330 /* show the wait waitq list */
331 if (i
== LHEAD_WAIT
) {
332 #ifdef HAVE_WAIT_QUEUE_HEAD_ENTRY
334 spl_wait_queue_entry_t
, entry
);
337 spl_wait_queue_entry_t
, task_list
);
340 seq_printf(f
, "\t%s:",
343 seq_printf(f
, "\n\t ");
346 seq_printf(f
, " %d", tsk
->pid
);
347 /* pend, prio and delay lists */
349 tqe
= list_entry(lh
, taskq_ent_t
,
352 seq_printf(f
, "\t%s:",
355 seq_printf(f
, "\n\t ");
357 seq_printf(f
, " %pf(%ps)",
365 if (lheads
[LHEAD_WAIT
])
366 spin_unlock_irqrestore(&tq
->tq_wait_waitq
.lock
, wflags
);
367 spin_unlock_irqrestore(&tq
->tq_lock
, flags
);
373 taskq_all_seq_show(struct seq_file
*f
, void *p
)
375 return (taskq_seq_show_impl(f
, p
, B_TRUE
));
379 taskq_seq_show(struct seq_file
*f
, void *p
)
381 return (taskq_seq_show_impl(f
, p
, B_FALSE
));
385 taskq_seq_start(struct seq_file
*f
, loff_t
*pos
)
390 down_read(&tq_list_sem
);
392 taskq_seq_show_headers(f
);
401 return (list_entry(p
, taskq_t
, tq_taskqs
));
405 taskq_seq_next(struct seq_file
*f
, void *p
, loff_t
*pos
)
410 return ((tq
->tq_taskqs
.next
== &tq_list
) ?
411 NULL
: list_entry(tq
->tq_taskqs
.next
, taskq_t
, tq_taskqs
));
415 slab_seq_show_headers(struct seq_file
*f
)
418 "--------------------- cache ----------"
419 "--------------------------------------------- "
422 "--- emergency ---\n");
425 " flags size alloc slabsize objsize "
428 "dlock alloc max\n");
432 slab_seq_show(struct seq_file
*f
, void *p
)
434 spl_kmem_cache_t
*skc
= p
;
436 ASSERT(skc
->skc_magic
== SKC_MAGIC
);
439 * Backed by Linux slab see /proc/slabinfo.
441 if (skc
->skc_flags
& KMC_SLAB
)
444 spin_lock(&skc
->skc_lock
);
445 seq_printf(f
, "%-36s ", skc
->skc_name
);
446 seq_printf(f
, "0x%05lx %9lu %9lu %8u %8u "
447 "%5lu %5lu %5lu %5lu %5lu %5lu %5lu %5lu %5lu\n",
448 (long unsigned)skc
->skc_flags
,
449 (long unsigned)(skc
->skc_slab_size
* skc
->skc_slab_total
),
450 (long unsigned)(skc
->skc_obj_size
* skc
->skc_obj_alloc
),
451 (unsigned)skc
->skc_slab_size
,
452 (unsigned)skc
->skc_obj_size
,
453 (long unsigned)skc
->skc_slab_total
,
454 (long unsigned)skc
->skc_slab_alloc
,
455 (long unsigned)skc
->skc_slab_max
,
456 (long unsigned)skc
->skc_obj_total
,
457 (long unsigned)skc
->skc_obj_alloc
,
458 (long unsigned)skc
->skc_obj_max
,
459 (long unsigned)skc
->skc_obj_deadlock
,
460 (long unsigned)skc
->skc_obj_emergency
,
461 (long unsigned)skc
->skc_obj_emergency_max
);
463 spin_unlock(&skc
->skc_lock
);
469 slab_seq_start(struct seq_file
*f
, loff_t
*pos
)
474 down_read(&spl_kmem_cache_sem
);
476 slab_seq_show_headers(f
);
478 p
= spl_kmem_cache_list
.next
;
481 if (p
== &spl_kmem_cache_list
)
485 return (list_entry(p
, spl_kmem_cache_t
, skc_list
));
489 slab_seq_next(struct seq_file
*f
, void *p
, loff_t
*pos
)
491 spl_kmem_cache_t
*skc
= p
;
494 return ((skc
->skc_list
.next
== &spl_kmem_cache_list
) ?
495 NULL
: list_entry(skc
->skc_list
.next
, spl_kmem_cache_t
, skc_list
));
499 slab_seq_stop(struct seq_file
*f
, void *v
)
501 up_read(&spl_kmem_cache_sem
);
504 static struct seq_operations slab_seq_ops
= {
505 .show
= slab_seq_show
,
506 .start
= slab_seq_start
,
507 .next
= slab_seq_next
,
508 .stop
= slab_seq_stop
,
512 proc_slab_open(struct inode
*inode
, struct file
*filp
)
514 return (seq_open(filp
, &slab_seq_ops
));
517 static struct file_operations proc_slab_operations
= {
518 .open
= proc_slab_open
,
521 .release
= seq_release
,
525 taskq_seq_stop(struct seq_file
*f
, void *v
)
527 up_read(&tq_list_sem
);
530 static struct seq_operations taskq_all_seq_ops
= {
531 .show
= taskq_all_seq_show
,
532 .start
= taskq_seq_start
,
533 .next
= taskq_seq_next
,
534 .stop
= taskq_seq_stop
,
537 static struct seq_operations taskq_seq_ops
= {
538 .show
= taskq_seq_show
,
539 .start
= taskq_seq_start
,
540 .next
= taskq_seq_next
,
541 .stop
= taskq_seq_stop
,
545 proc_taskq_all_open(struct inode
*inode
, struct file
*filp
)
547 return (seq_open(filp
, &taskq_all_seq_ops
));
551 proc_taskq_open(struct inode
*inode
, struct file
*filp
)
553 return (seq_open(filp
, &taskq_seq_ops
));
556 static struct file_operations proc_taskq_all_operations
= {
557 .open
= proc_taskq_all_open
,
560 .release
= seq_release
,
563 static struct file_operations proc_taskq_operations
= {
564 .open
= proc_taskq_open
,
567 .release
= seq_release
,
570 static struct ctl_table spl_kmem_table
[] = {
573 .procname
= "kmem_used",
574 .data
= &kmem_alloc_used
,
575 #ifdef HAVE_ATOMIC64_T
576 .maxlen
= sizeof (atomic64_t
),
578 .maxlen
= sizeof (atomic_t
),
579 #endif /* HAVE_ATOMIC64_T */
581 .proc_handler
= &proc_domemused
,
584 .procname
= "kmem_max",
585 .data
= &kmem_alloc_max
,
586 .maxlen
= sizeof (unsigned long),
587 .extra1
= &table_min
,
588 .extra2
= &table_max
,
590 .proc_handler
= &proc_doulongvec_minmax
,
592 #endif /* DEBUG_KMEM */
594 .procname
= "slab_kmem_total",
595 .data
= (void *)(KMC_KMEM
| KMC_TOTAL
),
596 .maxlen
= sizeof (unsigned long),
597 .extra1
= &table_min
,
598 .extra2
= &table_max
,
600 .proc_handler
= &proc_doslab
,
603 .procname
= "slab_kmem_alloc",
604 .data
= (void *)(KMC_KMEM
| KMC_ALLOC
),
605 .maxlen
= sizeof (unsigned long),
606 .extra1
= &table_min
,
607 .extra2
= &table_max
,
609 .proc_handler
= &proc_doslab
,
612 .procname
= "slab_kmem_max",
613 .data
= (void *)(KMC_KMEM
| KMC_MAX
),
614 .maxlen
= sizeof (unsigned long),
615 .extra1
= &table_min
,
616 .extra2
= &table_max
,
618 .proc_handler
= &proc_doslab
,
621 .procname
= "slab_vmem_total",
622 .data
= (void *)(KMC_VMEM
| KMC_TOTAL
),
623 .maxlen
= sizeof (unsigned long),
624 .extra1
= &table_min
,
625 .extra2
= &table_max
,
627 .proc_handler
= &proc_doslab
,
630 .procname
= "slab_vmem_alloc",
631 .data
= (void *)(KMC_VMEM
| KMC_ALLOC
),
632 .maxlen
= sizeof (unsigned long),
633 .extra1
= &table_min
,
634 .extra2
= &table_max
,
636 .proc_handler
= &proc_doslab
,
639 .procname
= "slab_vmem_max",
640 .data
= (void *)(KMC_VMEM
| KMC_MAX
),
641 .maxlen
= sizeof (unsigned long),
642 .extra1
= &table_min
,
643 .extra2
= &table_max
,
645 .proc_handler
= &proc_doslab
,
650 static struct ctl_table spl_kstat_table
[] = {
654 static struct ctl_table spl_table
[] = {
656 * NB No .strategy entries have been provided since
657 * sysctl(8) prefers to go via /proc for portability.
660 .procname
= "version",
662 .maxlen
= sizeof (spl_version
),
664 .proc_handler
= &proc_dostring
,
667 .procname
= "hostid",
669 .maxlen
= sizeof (unsigned long),
671 .proc_handler
= &proc_dohostid
,
676 .child
= spl_kmem_table
,
681 .child
= spl_kstat_table
,
686 static struct ctl_table spl_dir
[] = {
695 static struct ctl_table spl_root
[] = {
698 .ctl_name
= CTL_KERN
,
700 .procname
= "kernel",
712 spl_header
= register_sysctl_table(spl_root
);
713 if (spl_header
== NULL
)
716 proc_spl
= proc_mkdir("spl", NULL
);
717 if (proc_spl
== NULL
) {
722 proc_spl_taskq_all
= proc_create_data("taskq-all", 0444,
723 proc_spl
, &proc_taskq_all_operations
, NULL
);
724 if (proc_spl_taskq_all
== NULL
) {
729 proc_spl_taskq
= proc_create_data("taskq", 0444,
730 proc_spl
, &proc_taskq_operations
, NULL
);
731 if (proc_spl_taskq
== NULL
) {
736 proc_spl_kmem
= proc_mkdir("kmem", proc_spl
);
737 if (proc_spl_kmem
== NULL
) {
742 proc_spl_kmem_slab
= proc_create_data("slab", 0444,
743 proc_spl_kmem
, &proc_slab_operations
, NULL
);
744 if (proc_spl_kmem_slab
== NULL
) {
749 proc_spl_kstat
= proc_mkdir("kstat", proc_spl
);
750 if (proc_spl_kstat
== NULL
) {
756 remove_proc_entry("kstat", proc_spl
);
757 remove_proc_entry("slab", proc_spl_kmem
);
758 remove_proc_entry("kmem", proc_spl
);
759 remove_proc_entry("taskq-all", proc_spl
);
760 remove_proc_entry("taskq", proc_spl
);
761 remove_proc_entry("spl", NULL
);
762 unregister_sysctl_table(spl_header
);
771 remove_proc_entry("kstat", proc_spl
);
772 remove_proc_entry("slab", proc_spl_kmem
);
773 remove_proc_entry("kmem", proc_spl
);
774 remove_proc_entry("taskq-all", proc_spl
);
775 remove_proc_entry("taskq", proc_spl
);
776 remove_proc_entry("spl", NULL
);
778 ASSERT(spl_header
!= NULL
);
779 unregister_sysctl_table(spl_header
);