]> git.proxmox.com Git - mirror_spl-debian.git/blame - modules/spl/spl-proc.c
Apply a nice fix caught by Ricardo,
[mirror_spl-debian.git] / modules / spl / spl-proc.c
CommitLineData
715f6251 1/*
2 * This file is part of the SPL: Solaris Porting Layer.
3 *
4 * Copyright (c) 2008 Lawrence Livermore National Security, LLC.
5 * Produced at Lawrence Livermore National Laboratory
6 * Written by:
7 * Brian Behlendorf <behlendorf1@llnl.gov>,
8 * Herb Wartens <wartens2@llnl.gov>,
9 * Jim Garlick <garlick@llnl.gov>
10 * UCRL-CODE-235197
11 *
12 * This is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This is distributed in the hope that it will be useful, but WITHOUT
18 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 * for more details.
21 *
22 * You should have received a copy of the GNU General Public License along
23 * with this program; if not, write to the Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 */
26
04a479f7 27#include <sys/proc.h>
57d1b188 28
29#ifdef DEBUG_SUBSYSTEM
30#undef DEBUG_SUBSYSTEM
31#endif
32
33#define DEBUG_SUBSYSTEM S_PROC
34
404992e3 35#ifdef DEBUG_KMEM
57d1b188 36static unsigned long table_min = 0;
37static unsigned long table_max = ~0;
404992e3 38#endif
39
40#ifdef CONFIG_SYSCTL
41static struct ctl_table_header *spl_header = NULL;
c30df9c8 42#endif /* CONFIG_SYSCTL */
43
57d86234 44#if defined(DEBUG_MUTEX) || defined(DEBUG_KMEM) || defined(DEBUG_KSTAT)
c30df9c8 45static struct proc_dir_entry *proc_spl = NULL;
404992e3 46#ifdef DEBUG_MUTEX
c30df9c8 47static struct proc_dir_entry *proc_spl_mutex = NULL;
48static struct proc_dir_entry *proc_spl_mutex_stats = NULL;
49#endif /* DEBUG_MUTEX */
04a479f7 50#ifdef DEBUG_KMEM
c30df9c8 51static struct proc_dir_entry *proc_spl_kmem = NULL;
ff449ac4 52static struct proc_dir_entry *proc_spl_kmem_slab = NULL;
c30df9c8 53#endif /* DEBUG_KMEM */
04a479f7 54#ifdef DEBUG_KSTAT
c30df9c8 55struct proc_dir_entry *proc_spl_kstat = NULL;
56#endif /* DEBUG_KSTAT */
57#endif /* DEBUG_MUTEX || DEBUG_KMEM || DEBUG_KSTAT */
57d1b188 58
57d86234 59#ifdef HAVE_CTL_UNNUMBERED
60
61#define CTL_SPL CTL_UNNUMBERED
62#define CTL_SPL_DEBUG CTL_UNNUMBERED
63#define CTL_SPL_MUTEX CTL_UNNUMBERED
64#define CTL_SPL_KMEM CTL_UNNUMBERED
65#define CTL_SPL_KSTAT CTL_UNNUMBERED
66
67#define CTL_VERSION CTL_UNNUMBERED /* Version */
68#define CTL_HOSTID CTL_UNNUMBERED /* Host id by /usr/bin/hostid */
69#define CTL_HW_SERIAL CTL_UNNUMBERED /* HW serial number by hostid */
70
71#define CTL_DEBUG_SUBSYS CTL_UNNUMBERED /* Debug subsystem */
72#define CTL_DEBUG_MASK CTL_UNNUMBERED /* Debug mask */
73#define CTL_DEBUG_PRINTK CTL_UNNUMBERED /* All messages to console */
74#define CTL_DEBUG_MB CTL_UNNUMBERED /* Debug buffer size */
75#define CTL_DEBUG_BINARY CTL_UNNUMBERED /* Binary data in buffer */
76#define CTL_DEBUG_CATASTROPHE CTL_UNNUMBERED /* Set if BUG'd or panic'd */
77#define CTL_DEBUG_PANIC_ON_BUG CTL_UNNUMBERED /* Should panic on BUG */
78#define CTL_DEBUG_PATH CTL_UNNUMBERED /* Dump log location */
79#define CTL_DEBUG_DUMP CTL_UNNUMBERED /* Dump debug buffer to file */
80#define CTL_DEBUG_FORCE_BUG CTL_UNNUMBERED /* Hook to force a BUG */
81#define CTL_DEBUG_STACK_SIZE CTL_UNNUMBERED /* Max observed stack size */
82
83#define CTL_CONSOLE_RATELIMIT CTL_UNNUMBERED /* Ratelimit console messages */
84#define CTL_CONSOLE_MAX_DELAY_CS CTL_UNNUMBERED /* Max delay skip messages */
85#define CTL_CONSOLE_MIN_DELAY_CS CTL_UNNUMBERED /* Init delay skip messages */
86#define CTL_CONSOLE_BACKOFF CTL_UNNUMBERED /* Delay increase factor */
87
88#ifdef DEBUG_KMEM
89#define CTL_KMEM_KMEMUSED CTL_UNNUMBERED /* Alloc'd kmem bytes */
90#define CTL_KMEM_KMEMMAX CTL_UNNUMBERED /* Max alloc'd by kmem bytes */
91#define CTL_KMEM_VMEMUSED CTL_UNNUMBERED /* Alloc'd vmem bytes */
92#define CTL_KMEM_VMEMMAX CTL_UNNUMBERED /* Max alloc'd by vmem bytes */
93#define CTL_KMEM_ALLOC_FAILED CTL_UNNUMBERED /* Cache allocations failed */
94#endif
95
96#define CTL_MUTEX_STATS CTL_UNNUMBERED /* Global mutex statistics */
97#define CTL_MUTEX_STATS_PER CTL_UNNUMBERED /* Per mutex statistics */
98#define CTL_MUTEX_SPIN_MAX CTL_UNNUMBERED /* Max mutex spin iterations */
99
100#else /* HAVE_CTL_UNNUMBERED */
101
9ab1ac14 102#define CTL_SPL 0x87
103#define CTL_SPL_DEBUG 0x88
104#define CTL_SPL_MUTEX 0x89
105#define CTL_SPL_KMEM 0x90
04a479f7 106#define CTL_SPL_KSTAT 0x91
9ab1ac14 107
57d1b188 108enum {
3561541c 109 CTL_VERSION = 1, /* Version */
9ab1ac14 110 CTL_HOSTID, /* Host id reported by /usr/bin/hostid */
111 CTL_HW_SERIAL, /* Hardware serial number from hostid */
112
113 CTL_DEBUG_SUBSYS, /* Debug subsystem */
57d1b188 114 CTL_DEBUG_MASK, /* Debug mask */
115 CTL_DEBUG_PRINTK, /* Force all messages to console */
116 CTL_DEBUG_MB, /* Debug buffer size */
117 CTL_DEBUG_BINARY, /* Include binary data in buffer */
118 CTL_DEBUG_CATASTROPHE, /* Set if we have BUG'd or panic'd */
119 CTL_DEBUG_PANIC_ON_BUG, /* Set if we should panic on BUG */
120 CTL_DEBUG_PATH, /* Dump log location */
121 CTL_DEBUG_DUMP, /* Dump debug buffer to file */
122 CTL_DEBUG_FORCE_BUG, /* Hook to force a BUG */
9ab1ac14 123 CTL_DEBUG_STACK_SIZE, /* Max observed stack size */
124
125 CTL_CONSOLE_RATELIMIT, /* Ratelimit console messages */
57d1b188 126 CTL_CONSOLE_MAX_DELAY_CS, /* Max delay at which we skip messages */
127 CTL_CONSOLE_MIN_DELAY_CS, /* Init delay at which we skip messages */
128 CTL_CONSOLE_BACKOFF, /* Delay increase factor */
9ab1ac14 129
57d1b188 130#ifdef DEBUG_KMEM
57d86234 131 CTL_KMEM_KMEMUSED, /* Alloc'd kmem bytes */
57d1b188 132 CTL_KMEM_KMEMMAX, /* Max alloc'd by kmem bytes */
57d86234 133 CTL_KMEM_VMEMUSED, /* Alloc'd vmem bytes */
57d1b188 134 CTL_KMEM_VMEMMAX, /* Max alloc'd by vmem bytes */
135#endif
9ab1ac14 136
137 CTL_MUTEX_STATS, /* Global mutex statistics */
138 CTL_MUTEX_STATS_PER, /* Per mutex statistics */
139 CTL_MUTEX_SPIN_MAX, /* Maximum mutex spin iterations */
57d1b188 140};
57d86234 141#endif /* HAVE_CTL_UNNUMBERED */
57d1b188 142
143static int
144proc_copyin_string(char *kbuffer, int kbuffer_size,
145 const char *ubuffer, int ubuffer_size)
146{
147 int size;
148
149 if (ubuffer_size > kbuffer_size)
150 return -EOVERFLOW;
151
152 if (copy_from_user((void *)kbuffer, (void *)ubuffer, ubuffer_size))
153 return -EFAULT;
154
155 /* strip trailing whitespace */
156 size = strnlen(kbuffer, ubuffer_size);
157 while (size-- >= 0)
158 if (!isspace(kbuffer[size]))
159 break;
160
161 /* empty string */
162 if (size < 0)
163 return -EINVAL;
164
165 /* no space to terminate */
166 if (size == kbuffer_size)
167 return -EOVERFLOW;
168
169 kbuffer[size + 1] = 0;
170 return 0;
171}
172
173static int
174proc_copyout_string(char *ubuffer, int ubuffer_size,
175 const char *kbuffer, char *append)
176{
177 /* NB if 'append' != NULL, it's a single character to append to the
178 * copied out string - usually "\n", for /proc entries and
179 * (i.e. a terminating zero byte) for sysctl entries
180 */
181 int size = MIN(strlen(kbuffer), ubuffer_size);
182
183 if (copy_to_user(ubuffer, kbuffer, size))
184 return -EFAULT;
185
186 if (append != NULL && size < ubuffer_size) {
187 if (copy_to_user(ubuffer + size, append, 1))
188 return -EFAULT;
189
190 size++;
191 }
192
193 return size;
194}
195
196static int
197proc_dobitmasks(struct ctl_table *table, int write, struct file *filp,
198 void __user *buffer, size_t *lenp, loff_t *ppos)
199{
200 unsigned long *mask = table->data;
201 int is_subsys = (mask == &spl_debug_subsys) ? 1 : 0;
202 int is_printk = (mask == &spl_debug_printk) ? 1 : 0;
203 int size = 512, rc;
204 char *str;
205 ENTRY;
206
207 str = kmem_alloc(size, KM_SLEEP);
208 if (str == NULL)
209 RETURN(-ENOMEM);
210
211 if (write) {
212 rc = proc_copyin_string(str, size, buffer, *lenp);
213 if (rc < 0)
214 RETURN(rc);
215
216 rc = spl_debug_str2mask(mask, str, is_subsys);
217 /* Always print BUG/ASSERT to console, so keep this mask */
218 if (is_printk)
219 *mask |= D_EMERG;
220
221 *ppos += *lenp;
222 } else {
223 rc = spl_debug_mask2str(str, size, *mask, is_subsys);
224 if (*ppos >= rc)
225 rc = 0;
226 else
227 rc = proc_copyout_string(buffer, *lenp,
228 str + *ppos, "\n");
229 if (rc >= 0) {
230 *lenp = rc;
231 *ppos += rc;
232 }
233 }
234
235 kmem_free(str, size);
236 RETURN(rc);
237}
238
239static int
240proc_debug_mb(struct ctl_table *table, int write, struct file *filp,
241 void __user *buffer, size_t *lenp, loff_t *ppos)
242{
243 char str[32];
244 int rc, len;
245 ENTRY;
246
247 if (write) {
248 rc = proc_copyin_string(str, sizeof(str), buffer, *lenp);
249 if (rc < 0)
250 RETURN(rc);
251
252 rc = spl_debug_set_mb(simple_strtoul(str, NULL, 0));
253 *ppos += *lenp;
254 } else {
255 len = snprintf(str, sizeof(str), "%d", spl_debug_get_mb());
256 if (*ppos >= len)
257 rc = 0;
258 else
259 rc = proc_copyout_string(buffer, *lenp, str + *ppos, "\n");
260
261 if (rc >= 0) {
262 *lenp = rc;
263 *ppos += rc;
264 }
265 }
266
267 RETURN(rc);
268}
269
270static int
271proc_dump_kernel(struct ctl_table *table, int write, struct file *filp,
272 void __user *buffer, size_t *lenp, loff_t *ppos)
273{
274 ENTRY;
275
276 if (write) {
7fea96c0 277 spl_debug_dumplog(0);
57d1b188 278 *ppos += *lenp;
279 } else {
280 *lenp = 0;
281 }
282
283 RETURN(0);
284}
285
286static int
287proc_force_bug(struct ctl_table *table, int write, struct file *filp,
288 void __user *buffer, size_t *lenp, loff_t *ppos)
289{
290 ENTRY;
291
292 if (write) {
2fae1b3d 293 CERROR("Crashing due to forced SBUG\n");
294 SBUG();
57d1b188 295 /* Unreachable */
296 } else {
297 *lenp = 0;
298 }
299
300 RETURN(0);
301}
302
303static int
304proc_console_max_delay_cs(struct ctl_table *table, int write, struct file *filp,
305 void __user *buffer, size_t *lenp, loff_t *ppos)
306{
307 int rc, max_delay_cs;
308 struct ctl_table dummy = *table;
309 long d;
310 ENTRY;
311
312 dummy.data = &max_delay_cs;
313 dummy.proc_handler = &proc_dointvec;
314
315 if (write) {
316 max_delay_cs = 0;
317 rc = proc_dointvec(&dummy, write, filp, buffer, lenp, ppos);
318 if (rc < 0)
319 RETURN(rc);
320
321 if (max_delay_cs <= 0)
322 RETURN(-EINVAL);
323
324 d = (max_delay_cs * HZ) / 100;
325 if (d == 0 || d < spl_console_min_delay)
326 RETURN(-EINVAL);
327
328 spl_console_max_delay = d;
329 } else {
330 max_delay_cs = (spl_console_max_delay * 100) / HZ;
331 rc = proc_dointvec(&dummy, write, filp, buffer, lenp, ppos);
332 }
333
334 RETURN(rc);
335}
336
337static int
338proc_console_min_delay_cs(struct ctl_table *table, int write, struct file *filp,
339 void __user *buffer, size_t *lenp, loff_t *ppos)
340{
341 int rc, min_delay_cs;
342 struct ctl_table dummy = *table;
343 long d;
344 ENTRY;
345
346 dummy.data = &min_delay_cs;
347 dummy.proc_handler = &proc_dointvec;
348
349 if (write) {
350 min_delay_cs = 0;
351 rc = proc_dointvec(&dummy, write, filp, buffer, lenp, ppos);
352 if (rc < 0)
353 RETURN(rc);
354
355 if (min_delay_cs <= 0)
356 RETURN(-EINVAL);
357
358 d = (min_delay_cs * HZ) / 100;
359 if (d == 0 || d > spl_console_max_delay)
360 RETURN(-EINVAL);
361
362 spl_console_min_delay = d;
363 } else {
364 min_delay_cs = (spl_console_min_delay * 100) / HZ;
365 rc = proc_dointvec(&dummy, write, filp, buffer, lenp, ppos);
366 }
367
368 RETURN(rc);
369}
370
371static int
372proc_console_backoff(struct ctl_table *table, int write, struct file *filp,
373 void __user *buffer, size_t *lenp, loff_t *ppos)
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 = 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 = proc_dointvec(&dummy, write, filp, buffer, lenp, ppos);
395 }
396
397 RETURN(rc);
398}
399
c6dc93d6 400#ifdef DEBUG_KMEM
57d1b188 401static int
402proc_doatomic64(struct ctl_table *table, int write, struct file *filp,
403 void __user *buffer, size_t *lenp, loff_t *ppos)
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 val = atomic_read((atomic64_t *)table->data);
419 rc = proc_doulongvec_minmax(&dummy, write, filp,
420 buffer, lenp, ppos);
421 }
422
423 RETURN(rc);
424}
c6dc93d6 425#endif /* DEBUG_KMEM */
57d1b188 426
427static int
428proc_dohostid(struct ctl_table *table, int write, struct file *filp,
429 void __user *buffer, size_t *lenp, loff_t *ppos)
430{
431 int len, rc = 0;
937879f1 432 int32_t val;
57d1b188 433 char *end, str[32];
434 ENTRY;
435
436 if (write) {
437 /* We can't use 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
937879f1 444 val = simple_strtol(str, &end, 16);
57d1b188 445 if (str == end)
446 RETURN(-EINVAL);
447
937879f1 448 spl_hostid = (long)val;
449 sprintf(hw_serial, "%u", (val >= 0) ? val : -val);
57d1b188 450 *ppos += *lenp;
451 } else {
452 len = snprintf(str, sizeof(str), "%lx", spl_hostid);
453 if (*ppos >= len)
454 rc = 0;
455 else
456 rc = proc_copyout_string(buffer, *lenp, str + *ppos, "\n");
457
458 if (rc >= 0) {
459 *lenp = rc;
460 *ppos += rc;
461 }
462 }
463
464 RETURN(rc);
465}
466
9ab1ac14 467#ifdef DEBUG_MUTEX
468static void
469mutex_seq_show_headers(struct seq_file *f)
470{
471 seq_printf(f, "%-36s %-4s %-16s\t"
472 "e_tot\te_nh\te_sp\te_sl\tte_tot\tte_nh\n",
473 "name", "type", "owner");
474}
475
476static int
477mutex_seq_show(struct seq_file *f, void *p)
478{
479 kmutex_t *mp = p;
480 char t = 'X';
481 int i;
482
483 ASSERT(mp->km_magic == KM_MAGIC);
484
485 switch (mp->km_type) {
486 case MUTEX_DEFAULT: t = 'D'; break;
487 case MUTEX_SPIN: t = 'S'; break;
488 case MUTEX_ADAPTIVE: t = 'A'; break;
489 default:
490 SBUG();
491 }
492 seq_printf(f, "%-36s %c ", mp->km_name, t);
493 if (mp->km_owner)
494 seq_printf(f, "%p\t", mp->km_owner);
495 else
496 seq_printf(f, "%-16s\t", "<not held>");
497
498 for (i = 0; i < MUTEX_STATS_SIZE; i++)
499 seq_printf(f, "%d%c", mp->km_stats[i],
500 (i + 1 == MUTEX_STATS_SIZE) ? '\n' : '\t');
501
502 return 0;
503}
504
505static void *
506mutex_seq_start(struct seq_file *f, loff_t *pos)
507{
508 struct list_head *p;
509 loff_t n = *pos;
510 ENTRY;
511
404992e3 512 spin_lock(&mutex_stats_lock);
9ab1ac14 513 if (!n)
514 mutex_seq_show_headers(f);
515
516 p = mutex_stats_list.next;
517 while (n--) {
518 p = p->next;
519 if (p == &mutex_stats_list)
520 RETURN(NULL);
521 }
522
523 RETURN(list_entry(p, kmutex_t, km_list));
524}
525
526static void *
527mutex_seq_next(struct seq_file *f, void *p, loff_t *pos)
528{
529 kmutex_t *mp = p;
530 ENTRY;
531
532 ++*pos;
533 RETURN((mp->km_list.next == &mutex_stats_list) ?
534 NULL : list_entry(mp->km_list.next, kmutex_t, km_list));
535}
536
537static void
538mutex_seq_stop(struct seq_file *f, void *v)
539{
404992e3 540 spin_unlock(&mutex_stats_lock);
9ab1ac14 541}
542
543static struct seq_operations mutex_seq_ops = {
544 .show = mutex_seq_show,
545 .start = mutex_seq_start,
546 .next = mutex_seq_next,
547 .stop = mutex_seq_stop,
548};
549
550static int
551proc_mutex_open(struct inode *inode, struct file *filp)
552{
553 return seq_open(filp, &mutex_seq_ops);
554}
555
556static struct file_operations proc_mutex_operations = {
557 .open = proc_mutex_open,
558 .read = seq_read,
559 .llseek = seq_lseek,
560 .release = seq_release,
561};
562#endif /* DEBUG_MUTEX */
563
ff449ac4 564#ifdef DEBUG_KMEM
565static void
566slab_seq_show_headers(struct seq_file *f)
567{
568 seq_printf(f, "%-36s\n", "name");
569}
570
571static int
572slab_seq_show(struct seq_file *f, void *p)
573{
574 spl_kmem_cache_t *skc = p;
575
576 ASSERT(skc->skc_magic == SKC_MAGIC);
577
578 spin_lock(&skc->skc_lock);
579 seq_printf(f, "%-36s ", skc->skc_name);
a1502d76 580 seq_printf(f, "%u %u %u - %lu %lu %lu - %lu %lu %lu - %lu %lu %lu\n",
ff449ac4 581 (unsigned)skc->skc_obj_size,
a1502d76 582 (unsigned)skc->skc_slab_objs,
ff449ac4 583 (unsigned)skc->skc_slab_size,
ff449ac4 584 (long unsigned)skc->skc_slab_fail,
585 (long unsigned)skc->skc_slab_create,
586 (long unsigned)skc->skc_slab_destroy,
587 (long unsigned)skc->skc_slab_total,
588 (long unsigned)skc->skc_slab_alloc,
589 (long unsigned)skc->skc_slab_max,
590 (long unsigned)skc->skc_obj_total,
591 (long unsigned)skc->skc_obj_alloc,
a1502d76 592 (long unsigned)skc->skc_obj_max);
ff449ac4 593
594 spin_unlock(&skc->skc_lock);
595
596 return 0;
597}
598
599static void *
600slab_seq_start(struct seq_file *f, loff_t *pos)
601{
602 struct list_head *p;
603 loff_t n = *pos;
604 ENTRY;
605
606 down_read(&spl_kmem_cache_sem);
607 if (!n)
608 slab_seq_show_headers(f);
609
610 p = spl_kmem_cache_list.next;
611 while (n--) {
612 p = p->next;
613 if (p == &spl_kmem_cache_list)
614 RETURN(NULL);
615 }
616
617 RETURN(list_entry(p, spl_kmem_cache_t, skc_list));
618}
619
620static void *
621slab_seq_next(struct seq_file *f, void *p, loff_t *pos)
622{
623 spl_kmem_cache_t *skc = p;
624 ENTRY;
625
626 ++*pos;
627 RETURN((skc->skc_list.next == &spl_kmem_cache_list) ?
628 NULL : list_entry(skc->skc_list.next, spl_kmem_cache_t, skc_list));
629}
630
631static void
632slab_seq_stop(struct seq_file *f, void *v)
633{
634 up_read(&spl_kmem_cache_sem);
635}
636
637static struct seq_operations slab_seq_ops = {
638 .show = slab_seq_show,
639 .start = slab_seq_start,
640 .next = slab_seq_next,
641 .stop = slab_seq_stop,
642};
643
644static int
645proc_slab_open(struct inode *inode, struct file *filp)
646{
647 return seq_open(filp, &slab_seq_ops);
648}
649
650static struct file_operations proc_slab_operations = {
651 .open = proc_slab_open,
652 .read = seq_read,
653 .llseek = seq_lseek,
654 .release = seq_release,
655};
656#endif /* DEBUG_KMEM */
657
9ab1ac14 658static struct ctl_table spl_debug_table[] = {
57d1b188 659 {
660 .ctl_name = CTL_DEBUG_SUBSYS,
9ab1ac14 661 .procname = "subsystem",
57d1b188 662 .data = &spl_debug_subsys,
663 .maxlen = sizeof(unsigned long),
664 .mode = 0644,
665 .proc_handler = &proc_dobitmasks
666 },
667 {
668 .ctl_name = CTL_DEBUG_MASK,
9ab1ac14 669 .procname = "mask",
57d1b188 670 .data = &spl_debug_mask,
671 .maxlen = sizeof(unsigned long),
672 .mode = 0644,
673 .proc_handler = &proc_dobitmasks
674 },
675 {
676 .ctl_name = CTL_DEBUG_PRINTK,
9ab1ac14 677 .procname = "printk",
57d1b188 678 .data = &spl_debug_printk,
679 .maxlen = sizeof(unsigned long),
680 .mode = 0644,
681 .proc_handler = &proc_dobitmasks
682 },
683 {
684 .ctl_name = CTL_DEBUG_MB,
9ab1ac14 685 .procname = "mb",
57d1b188 686 .mode = 0644,
687 .proc_handler = &proc_debug_mb,
688 },
689 {
690 .ctl_name = CTL_DEBUG_BINARY,
9ab1ac14 691 .procname = "binary",
57d1b188 692 .data = &spl_debug_binary,
693 .maxlen = sizeof(int),
694 .mode = 0644,
695 .proc_handler = &proc_dointvec,
696 },
697 {
698 .ctl_name = CTL_DEBUG_CATASTROPHE,
699 .procname = "catastrophe",
700 .data = &spl_debug_catastrophe,
701 .maxlen = sizeof(int),
702 .mode = 0444,
703 .proc_handler = &proc_dointvec,
704 },
705 {
706 .ctl_name = CTL_DEBUG_PANIC_ON_BUG,
707 .procname = "panic_on_bug",
708 .data = &spl_debug_panic_on_bug,
709 .maxlen = sizeof(int),
710 .mode = 0644,
711 .proc_handler = &proc_dointvec
712 },
713 {
714 .ctl_name = CTL_DEBUG_PATH,
9ab1ac14 715 .procname = "path",
57d1b188 716 .data = spl_debug_file_path,
717 .maxlen = sizeof(spl_debug_file_path),
718 .mode = 0644,
719 .proc_handler = &proc_dostring,
720 },
721 {
722 .ctl_name = CTL_DEBUG_DUMP,
9ab1ac14 723 .procname = "dump",
57d1b188 724 .mode = 0200,
725 .proc_handler = &proc_dump_kernel,
726 },
727 { .ctl_name = CTL_DEBUG_FORCE_BUG,
728 .procname = "force_bug",
729 .mode = 0200,
730 .proc_handler = &proc_force_bug,
731 },
732 {
733 .ctl_name = CTL_CONSOLE_RATELIMIT,
734 .procname = "console_ratelimit",
735 .data = &spl_console_ratelimit,
736 .maxlen = sizeof(int),
737 .mode = 0644,
738 .proc_handler = &proc_dointvec,
739 },
740 {
741 .ctl_name = CTL_CONSOLE_MAX_DELAY_CS,
742 .procname = "console_max_delay_centisecs",
743 .maxlen = sizeof(int),
744 .mode = 0644,
745 .proc_handler = &proc_console_max_delay_cs,
746 },
747 {
748 .ctl_name = CTL_CONSOLE_MIN_DELAY_CS,
749 .procname = "console_min_delay_centisecs",
750 .maxlen = sizeof(int),
751 .mode = 0644,
752 .proc_handler = &proc_console_min_delay_cs,
753 },
754 {
755 .ctl_name = CTL_CONSOLE_BACKOFF,
756 .procname = "console_backoff",
757 .maxlen = sizeof(int),
758 .mode = 0644,
759 .proc_handler = &proc_console_backoff,
760 },
761 {
9ab1ac14 762 .ctl_name = CTL_DEBUG_STACK_SIZE,
57d1b188 763 .procname = "stack_max",
764 .data = &spl_debug_stack,
765 .maxlen = sizeof(int),
766 .mode = 0444,
767 .proc_handler = &proc_dointvec,
768 },
9ab1ac14 769 {0},
770};
771
772#ifdef DEBUG_MUTEX
773static struct ctl_table spl_mutex_table[] = {
774 {
775 .ctl_name = CTL_MUTEX_STATS,
776 .procname = "stats",
777 .data = &mutex_stats,
778 .maxlen = sizeof(int) * MUTEX_STATS_SIZE,
779 .mode = 0444,
780 .proc_handler = &proc_dointvec,
781 },
782 {
783 .ctl_name = CTL_MUTEX_SPIN_MAX,
784 .procname = "spin_max",
785 .data = &mutex_spin_max,
786 .maxlen = sizeof(int),
787 .mode = 0644,
788 .proc_handler = &proc_dointvec,
789 },
790 {0},
791};
792#endif /* DEBUG_MUTEX */
793
57d1b188 794#ifdef DEBUG_KMEM
9ab1ac14 795static struct ctl_table spl_kmem_table[] = {
57d1b188 796 {
797 .ctl_name = CTL_KMEM_KMEMUSED,
798 .procname = "kmem_used",
799 .data = &kmem_alloc_used,
800 .maxlen = sizeof(atomic64_t),
801 .mode = 0444,
802 .proc_handler = &proc_doatomic64,
803 },
804 {
805 .ctl_name = CTL_KMEM_KMEMMAX,
806 .procname = "kmem_max",
807 .data = &kmem_alloc_max,
808 .maxlen = sizeof(unsigned long),
809 .extra1 = &table_min,
810 .extra2 = &table_max,
811 .mode = 0444,
812 .proc_handler = &proc_doulongvec_minmax,
813 },
814 {
815 .ctl_name = CTL_KMEM_VMEMUSED,
816 .procname = "vmem_used",
817 .data = &vmem_alloc_used,
818 .maxlen = sizeof(atomic64_t),
819 .mode = 0444,
820 .proc_handler = &proc_doatomic64,
821 },
822 {
823 .ctl_name = CTL_KMEM_VMEMMAX,
824 .procname = "vmem_max",
825 .data = &vmem_alloc_max,
826 .maxlen = sizeof(unsigned long),
827 .extra1 = &table_min,
828 .extra2 = &table_max,
829 .mode = 0444,
830 .proc_handler = &proc_doulongvec_minmax,
831 },
9ab1ac14 832 {0},
833};
04a479f7 834#endif /* DEBUG_KMEM */
835
836#ifdef DEBUG_KSTAT
837static struct ctl_table spl_kstat_table[] = {
838 {0},
839};
840#endif /* DEBUG_KSTAT */
9ab1ac14 841
842static struct ctl_table spl_table[] = {
843 /* NB No .strategy entries have been provided since
844 * sysctl(8) prefers to go via /proc for portability.
845 */
846 {
847 .ctl_name = CTL_VERSION,
848 .procname = "version",
849 .data = spl_version,
850 .maxlen = sizeof(spl_version),
851 .mode = 0444,
852 .proc_handler = &proc_dostring,
853 },
57d1b188 854 {
855 .ctl_name = CTL_HOSTID,
856 .procname = "hostid",
857 .data = &spl_hostid,
858 .maxlen = sizeof(unsigned long),
859 .mode = 0644,
860 .proc_handler = &proc_dohostid,
861 },
862 {
863 .ctl_name = CTL_HW_SERIAL,
864 .procname = "hw_serial",
937879f1 865 .data = hw_serial,
866 .maxlen = sizeof(hw_serial),
57d1b188 867 .mode = 0444,
868 .proc_handler = &proc_dostring,
869 },
9ab1ac14 870 {
871 .ctl_name = CTL_SPL_DEBUG,
872 .procname = "debug",
873 .mode = 0555,
874 .child = spl_debug_table,
875 },
876#ifdef DEBUG_MUTEX
877 {
878 .ctl_name = CTL_SPL_MUTEX,
879 .procname = "mutex",
880 .mode = 0555,
881 .child = spl_mutex_table,
882 },
883#endif
884#ifdef DEBUG_KMEM
885 {
886 .ctl_name = CTL_SPL_KMEM,
887 .procname = "kmem",
888 .mode = 0555,
889 .child = spl_kmem_table,
890 },
04a479f7 891#endif
892#ifdef DEBUG_KSTAT
893 {
894 .ctl_name = CTL_SPL_KSTAT,
895 .procname = "kstat",
896 .mode = 0555,
897 .child = spl_kstat_table,
898 },
9ab1ac14 899#endif
57d1b188 900 { 0 },
901};
902
9ab1ac14 903static struct ctl_table spl_dir[] = {
57d1b188 904 {
905 .ctl_name = CTL_SPL,
906 .procname = "spl",
907 .mode = 0555,
908 .child = spl_table,
909 },
57d86234 910 { 0 }
911};
912
913static struct ctl_table spl_root[] = {
914 {
915 .ctl_name = CTL_KERN,
916 .procname = "kernel",
917 .mode = 0555,
918 .child = spl_dir,
919 },
920 { 0 }
57d1b188 921};
922
404992e3 923static int
924proc_dir_entry_match(int len, const char *name, struct proc_dir_entry *de)
925{
926 if (de->namelen != len)
927 return 0;
928
929 return !memcmp(name, de->name, len);
930}
931
04a479f7 932struct proc_dir_entry *
404992e3 933proc_dir_entry_find(struct proc_dir_entry *root, const char *str)
934{
935 struct proc_dir_entry *de;
936
937 for (de = root->subdir; de; de = de->next)
938 if (proc_dir_entry_match(strlen(str), str, de))
939 return de;
940
941 return NULL;
942}
943
04a479f7 944int
945proc_dir_entries(struct proc_dir_entry *root)
946{
947 struct proc_dir_entry *de;
948 int i = 0;
949
950 for (de = root->subdir; de; de = de->next)
951 i++;
952
953 return i;
954}
955
57d1b188 956int
957proc_init(void)
958{
404992e3 959 int rc = 0;
57d1b188 960 ENTRY;
961
962#ifdef CONFIG_SYSCTL
57d86234 963 spl_header = spl_register_sysctl_table(spl_root, 0);
57d1b188 964 if (spl_header == NULL)
965 RETURN(-EUNATCH);
c30df9c8 966#endif /* CONFIG_SYSCTL */
9ab1ac14 967
57d86234 968#if defined(DEBUG_MUTEX) || defined(DEBUG_KMEM) || defined(DEBUG_KSTAT)
c30df9c8 969 proc_spl = proc_mkdir("spl", NULL);
970 if (proc_spl == NULL)
404992e3 971 GOTO(out, rc = -EUNATCH);
972
9ab1ac14 973#ifdef DEBUG_MUTEX
c30df9c8 974 proc_spl_mutex = proc_mkdir("mutex", proc_spl);
975 if (proc_spl_mutex == NULL)
404992e3 976 GOTO(out, rc = -EUNATCH);
977
c30df9c8 978 proc_spl_mutex_stats = create_proc_entry("stats_per", 0444,
979 proc_spl_mutex);
980 if (proc_spl_mutex_stats == NULL)
404992e3 981 GOTO(out, rc = -EUNATCH);
982
c30df9c8 983 proc_spl_mutex_stats->proc_fops = &proc_mutex_operations;
9ab1ac14 984#endif /* DEBUG_MUTEX */
04a479f7 985
986#ifdef DEBUG_KMEM
c30df9c8 987 proc_spl_kmem = proc_mkdir("kmem", proc_spl);
988 if (proc_spl_kmem == NULL)
989 GOTO(out, rc = -EUNATCH);
ff449ac4 990
991 proc_spl_kmem_slab = create_proc_entry("slab", 0444, proc_spl_kmem);
992 if (proc_spl_kmem_slab == NULL)
993 GOTO(out, rc = -EUNATCH);
994
995 proc_spl_kmem_slab->proc_fops = &proc_slab_operations;
04a479f7 996#endif /* DEBUG_KMEM */
997
998#ifdef DEBUG_KSTAT
c30df9c8 999 proc_spl_kstat = proc_mkdir("kstat", proc_spl);
1000 if (proc_spl_kstat == NULL)
1001 GOTO(out, rc = -EUNATCH);
04a479f7 1002#endif /* DEBUG_KSTAT */
1003
404992e3 1004out:
c30df9c8 1005 if (rc) {
1006 remove_proc_entry("kstat", proc_spl);
ff449ac4 1007#ifdef DEBUG_KMEM
1008 remove_proc_entry("slab", proc_spl_kmem);
1009#endif
c30df9c8 1010 remove_proc_entry("kmem", proc_spl);
4afaaefa 1011#ifdef DEBUG_MUTEX
c30df9c8 1012 remove_proc_entry("stats_per", proc_spl_mutex);
4afaaefa 1013#endif
c30df9c8 1014 remove_proc_entry("mutex", proc_spl);
a02118a8 1015 remove_proc_entry("spl", NULL);
c30df9c8 1016#ifdef CONFIG_SYSCTL
1017 spl_unregister_sysctl_table(spl_header);
404992e3 1018#endif /* CONFIG_SYSCTL */
c30df9c8 1019 }
1020#endif /* DEBUG_MUTEX || DEBUG_KMEM || DEBUG_KSTAT */
1021
404992e3 1022 RETURN(rc);
57d1b188 1023}
1024
1025void
1026proc_fini(void)
1027{
1028 ENTRY;
1029
c30df9c8 1030#if defined(DEBUG_MUTEX) || defined(DEBUG_KMEM) || defined(DEBUG_KSTAT)
1031 remove_proc_entry("kstat", proc_spl);
ff449ac4 1032#ifdef DEBUG_KMEM
1033 remove_proc_entry("slab", proc_spl_kmem);
1034#endif
c30df9c8 1035 remove_proc_entry("kmem", proc_spl);
4afaaefa 1036#ifdef DEBUG_MUTEX
c30df9c8 1037 remove_proc_entry("stats_per", proc_spl_mutex);
4afaaefa 1038#endif
c30df9c8 1039 remove_proc_entry("mutex", proc_spl);
a02118a8 1040 remove_proc_entry("spl", NULL);
c30df9c8 1041#endif /* DEBUG_MUTEX || DEBUG_KMEM || DEBUG_KSTAT */
1042
57d1b188 1043#ifdef CONFIG_SYSCTL
1044 ASSERT(spl_header != NULL);
57d86234 1045 spl_unregister_sysctl_table(spl_header);
c30df9c8 1046#endif /* CONFIG_SYSCTL */
1047
57d1b188 1048 EXIT;
1049}