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
, const char *kbuffer
,
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
243 static unsigned int spl_max_show_tasks
= 512;
244 module_param(spl_max_show_tasks
, uint
, 0644);
245 MODULE_PARM_DESC(spl_max_show_tasks
, "Max number of tasks shown in taskq proc");
249 taskq_seq_show_impl(struct seq_file
*f
, void *p
, boolean_t allflag
)
253 spl_wait_queue_entry_t
*wq
;
254 struct task_struct
*tsk
;
257 struct list_head
*lheads
[LHEAD_SIZE
], *lh
;
258 static char *list_names
[LHEAD_SIZE
] =
259 {"pend", "prio", "delay", "wait", "active" };
260 int i
, j
, have_lheads
= 0;
261 unsigned long wflags
, flags
;
263 spin_lock_irqsave_nested(&tq
->tq_lock
, flags
, tq
->tq_lock_class
);
264 spin_lock_irqsave(&tq
->tq_wait_waitq
.lock
, wflags
);
266 /* get the various lists and check whether they're empty */
267 lheads
[LHEAD_PEND
] = &tq
->tq_pend_list
;
268 lheads
[LHEAD_PRIO
] = &tq
->tq_prio_list
;
269 lheads
[LHEAD_DELAY
] = &tq
->tq_delay_list
;
270 #ifdef HAVE_WAIT_QUEUE_HEAD_ENTRY
271 lheads
[LHEAD_WAIT
] = &tq
->tq_wait_waitq
.head
;
273 lheads
[LHEAD_WAIT
] = &tq
->tq_wait_waitq
.task_list
;
275 lheads
[LHEAD_ACTIVE
] = &tq
->tq_active_list
;
277 for (i
= 0; i
< LHEAD_SIZE
; ++i
) {
278 if (list_empty(lheads
[i
]))
284 /* early return in non-"all" mode if lists are all empty */
285 if (!allflag
&& !have_lheads
) {
286 spin_unlock_irqrestore(&tq
->tq_wait_waitq
.lock
, wflags
);
287 spin_unlock_irqrestore(&tq
->tq_lock
, flags
);
291 /* unlock the waitq quickly */
292 if (!lheads
[LHEAD_WAIT
])
293 spin_unlock_irqrestore(&tq
->tq_wait_waitq
.lock
, wflags
);
295 /* show the base taskq contents */
296 snprintf(name
, sizeof (name
), "%s/%d", tq
->tq_name
, tq
->tq_instance
);
297 seq_printf(f
, "%-25s ", name
);
298 seq_printf(f
, "%5d %5d %5d %5d %5d %5d %12d %5d %10x\n",
299 tq
->tq_nactive
, tq
->tq_nthreads
, tq
->tq_nspawn
,
300 tq
->tq_maxthreads
, tq
->tq_pri
, tq
->tq_minalloc
, tq
->tq_maxalloc
,
301 tq
->tq_nalloc
, tq
->tq_flags
);
303 /* show the active list */
304 if (lheads
[LHEAD_ACTIVE
]) {
306 list_for_each_entry(tqt
, &tq
->tq_active_list
, tqt_active_list
) {
308 seq_printf(f
, "\t%s:",
309 list_names
[LHEAD_ACTIVE
]);
311 seq_printf(f
, "\n\t ");
314 seq_printf(f
, " [%d]%pf(%ps)",
315 tqt
->tqt_thread
->pid
,
316 tqt
->tqt_task
->tqent_func
,
317 tqt
->tqt_task
->tqent_arg
);
323 for (i
= LHEAD_PEND
; i
<= LHEAD_WAIT
; ++i
)
326 list_for_each(lh
, lheads
[i
]) {
327 if (spl_max_show_tasks
!= 0 &&
328 j
>= spl_max_show_tasks
) {
329 seq_printf(f
, "\n\t(truncated)");
332 /* show the wait waitq list */
333 if (i
== LHEAD_WAIT
) {
334 #ifdef HAVE_WAIT_QUEUE_HEAD_ENTRY
336 spl_wait_queue_entry_t
, entry
);
339 spl_wait_queue_entry_t
, task_list
);
342 seq_printf(f
, "\t%s:",
345 seq_printf(f
, "\n\t ");
348 seq_printf(f
, " %d", tsk
->pid
);
349 /* pend, prio and delay lists */
351 tqe
= list_entry(lh
, taskq_ent_t
,
354 seq_printf(f
, "\t%s:",
357 seq_printf(f
, "\n\t ");
359 seq_printf(f
, " %pf(%ps)",
367 if (lheads
[LHEAD_WAIT
])
368 spin_unlock_irqrestore(&tq
->tq_wait_waitq
.lock
, wflags
);
369 spin_unlock_irqrestore(&tq
->tq_lock
, flags
);
375 taskq_all_seq_show(struct seq_file
*f
, void *p
)
377 return (taskq_seq_show_impl(f
, p
, B_TRUE
));
381 taskq_seq_show(struct seq_file
*f
, void *p
)
383 return (taskq_seq_show_impl(f
, p
, B_FALSE
));
387 taskq_seq_start(struct seq_file
*f
, loff_t
*pos
)
392 down_read(&tq_list_sem
);
394 taskq_seq_show_headers(f
);
403 return (list_entry(p
, taskq_t
, tq_taskqs
));
407 taskq_seq_next(struct seq_file
*f
, void *p
, loff_t
*pos
)
412 return ((tq
->tq_taskqs
.next
== &tq_list
) ?
413 NULL
: list_entry(tq
->tq_taskqs
.next
, taskq_t
, tq_taskqs
));
417 slab_seq_show_headers(struct seq_file
*f
)
420 "--------------------- cache ----------"
421 "--------------------------------------------- "
424 "--- emergency ---\n");
427 " flags size alloc slabsize objsize "
430 "dlock alloc max\n");
434 slab_seq_show(struct seq_file
*f
, void *p
)
436 spl_kmem_cache_t
*skc
= p
;
438 ASSERT(skc
->skc_magic
== SKC_MAGIC
);
441 * Backed by Linux slab see /proc/slabinfo.
443 if (skc
->skc_flags
& KMC_SLAB
)
446 spin_lock(&skc
->skc_lock
);
447 seq_printf(f
, "%-36s ", skc
->skc_name
);
448 seq_printf(f
, "0x%05lx %9lu %9lu %8u %8u "
449 "%5lu %5lu %5lu %5lu %5lu %5lu %5lu %5lu %5lu\n",
450 (long unsigned)skc
->skc_flags
,
451 (long unsigned)(skc
->skc_slab_size
* skc
->skc_slab_total
),
452 (long unsigned)(skc
->skc_obj_size
* skc
->skc_obj_alloc
),
453 (unsigned)skc
->skc_slab_size
,
454 (unsigned)skc
->skc_obj_size
,
455 (long unsigned)skc
->skc_slab_total
,
456 (long unsigned)skc
->skc_slab_alloc
,
457 (long unsigned)skc
->skc_slab_max
,
458 (long unsigned)skc
->skc_obj_total
,
459 (long unsigned)skc
->skc_obj_alloc
,
460 (long unsigned)skc
->skc_obj_max
,
461 (long unsigned)skc
->skc_obj_deadlock
,
462 (long unsigned)skc
->skc_obj_emergency
,
463 (long unsigned)skc
->skc_obj_emergency_max
);
465 spin_unlock(&skc
->skc_lock
);
471 slab_seq_start(struct seq_file
*f
, loff_t
*pos
)
476 down_read(&spl_kmem_cache_sem
);
478 slab_seq_show_headers(f
);
480 p
= spl_kmem_cache_list
.next
;
483 if (p
== &spl_kmem_cache_list
)
487 return (list_entry(p
, spl_kmem_cache_t
, skc_list
));
491 slab_seq_next(struct seq_file
*f
, void *p
, loff_t
*pos
)
493 spl_kmem_cache_t
*skc
= p
;
496 return ((skc
->skc_list
.next
== &spl_kmem_cache_list
) ?
497 NULL
: list_entry(skc
->skc_list
.next
, spl_kmem_cache_t
, skc_list
));
501 slab_seq_stop(struct seq_file
*f
, void *v
)
503 up_read(&spl_kmem_cache_sem
);
506 static struct seq_operations slab_seq_ops
= {
507 .show
= slab_seq_show
,
508 .start
= slab_seq_start
,
509 .next
= slab_seq_next
,
510 .stop
= slab_seq_stop
,
514 proc_slab_open(struct inode
*inode
, struct file
*filp
)
516 return (seq_open(filp
, &slab_seq_ops
));
519 static struct file_operations proc_slab_operations
= {
520 .open
= proc_slab_open
,
523 .release
= seq_release
,
527 taskq_seq_stop(struct seq_file
*f
, void *v
)
529 up_read(&tq_list_sem
);
532 static struct seq_operations taskq_all_seq_ops
= {
533 .show
= taskq_all_seq_show
,
534 .start
= taskq_seq_start
,
535 .next
= taskq_seq_next
,
536 .stop
= taskq_seq_stop
,
539 static struct seq_operations taskq_seq_ops
= {
540 .show
= taskq_seq_show
,
541 .start
= taskq_seq_start
,
542 .next
= taskq_seq_next
,
543 .stop
= taskq_seq_stop
,
547 proc_taskq_all_open(struct inode
*inode
, struct file
*filp
)
549 return (seq_open(filp
, &taskq_all_seq_ops
));
553 proc_taskq_open(struct inode
*inode
, struct file
*filp
)
555 return (seq_open(filp
, &taskq_seq_ops
));
558 static struct file_operations proc_taskq_all_operations
= {
559 .open
= proc_taskq_all_open
,
562 .release
= seq_release
,
565 static struct file_operations proc_taskq_operations
= {
566 .open
= proc_taskq_open
,
569 .release
= seq_release
,
572 static struct ctl_table spl_kmem_table
[] = {
575 .procname
= "kmem_used",
576 .data
= &kmem_alloc_used
,
577 #ifdef HAVE_ATOMIC64_T
578 .maxlen
= sizeof (atomic64_t
),
580 .maxlen
= sizeof (atomic_t
),
581 #endif /* HAVE_ATOMIC64_T */
583 .proc_handler
= &proc_domemused
,
586 .procname
= "kmem_max",
587 .data
= &kmem_alloc_max
,
588 .maxlen
= sizeof (unsigned long),
589 .extra1
= &table_min
,
590 .extra2
= &table_max
,
592 .proc_handler
= &proc_doulongvec_minmax
,
594 #endif /* DEBUG_KMEM */
596 .procname
= "slab_kmem_total",
597 .data
= (void *)(KMC_KMEM
| KMC_TOTAL
),
598 .maxlen
= sizeof (unsigned long),
599 .extra1
= &table_min
,
600 .extra2
= &table_max
,
602 .proc_handler
= &proc_doslab
,
605 .procname
= "slab_kmem_alloc",
606 .data
= (void *)(KMC_KMEM
| KMC_ALLOC
),
607 .maxlen
= sizeof (unsigned long),
608 .extra1
= &table_min
,
609 .extra2
= &table_max
,
611 .proc_handler
= &proc_doslab
,
614 .procname
= "slab_kmem_max",
615 .data
= (void *)(KMC_KMEM
| KMC_MAX
),
616 .maxlen
= sizeof (unsigned long),
617 .extra1
= &table_min
,
618 .extra2
= &table_max
,
620 .proc_handler
= &proc_doslab
,
623 .procname
= "slab_vmem_total",
624 .data
= (void *)(KMC_VMEM
| KMC_TOTAL
),
625 .maxlen
= sizeof (unsigned long),
626 .extra1
= &table_min
,
627 .extra2
= &table_max
,
629 .proc_handler
= &proc_doslab
,
632 .procname
= "slab_vmem_alloc",
633 .data
= (void *)(KMC_VMEM
| KMC_ALLOC
),
634 .maxlen
= sizeof (unsigned long),
635 .extra1
= &table_min
,
636 .extra2
= &table_max
,
638 .proc_handler
= &proc_doslab
,
641 .procname
= "slab_vmem_max",
642 .data
= (void *)(KMC_VMEM
| KMC_MAX
),
643 .maxlen
= sizeof (unsigned long),
644 .extra1
= &table_min
,
645 .extra2
= &table_max
,
647 .proc_handler
= &proc_doslab
,
652 static struct ctl_table spl_kstat_table
[] = {
656 static struct ctl_table spl_table
[] = {
658 * NB No .strategy entries have been provided since
659 * sysctl(8) prefers to go via /proc for portability.
662 .procname
= "version",
664 .maxlen
= sizeof (spl_version
),
666 .proc_handler
= &proc_dostring
,
669 .procname
= "hostid",
671 .maxlen
= sizeof (unsigned long),
673 .proc_handler
= &proc_dohostid
,
678 .child
= spl_kmem_table
,
683 .child
= spl_kstat_table
,
688 static struct ctl_table spl_dir
[] = {
697 static struct ctl_table spl_root
[] = {
700 .ctl_name
= CTL_KERN
,
702 .procname
= "kernel",
714 spl_header
= register_sysctl_table(spl_root
);
715 if (spl_header
== NULL
)
718 proc_spl
= proc_mkdir("spl", NULL
);
719 if (proc_spl
== NULL
) {
724 proc_spl_taskq_all
= proc_create_data("taskq-all", 0444, proc_spl
,
725 &proc_taskq_all_operations
, NULL
);
726 if (proc_spl_taskq_all
== NULL
) {
731 proc_spl_taskq
= proc_create_data("taskq", 0444, proc_spl
,
732 &proc_taskq_operations
, NULL
);
733 if (proc_spl_taskq
== NULL
) {
738 proc_spl_kmem
= proc_mkdir("kmem", proc_spl
);
739 if (proc_spl_kmem
== NULL
) {
744 proc_spl_kmem_slab
= proc_create_data("slab", 0444, proc_spl_kmem
,
745 &proc_slab_operations
, NULL
);
746 if (proc_spl_kmem_slab
== NULL
) {
751 proc_spl_kstat
= proc_mkdir("kstat", proc_spl
);
752 if (proc_spl_kstat
== NULL
) {
758 remove_proc_entry("kstat", proc_spl
);
759 remove_proc_entry("slab", proc_spl_kmem
);
760 remove_proc_entry("kmem", proc_spl
);
761 remove_proc_entry("taskq-all", proc_spl
);
762 remove_proc_entry("taskq", proc_spl
);
763 remove_proc_entry("spl", NULL
);
764 unregister_sysctl_table(spl_header
);
773 remove_proc_entry("kstat", proc_spl
);
774 remove_proc_entry("slab", proc_spl_kmem
);
775 remove_proc_entry("kmem", proc_spl
);
776 remove_proc_entry("taskq-all", proc_spl
);
777 remove_proc_entry("taskq", proc_spl
);
778 remove_proc_entry("spl", NULL
);
780 ASSERT(spl_header
!= NULL
);
781 unregister_sysctl_table(spl_header
);