]> git.proxmox.com Git - mirror_spl.git/blob - module/spl/spl-proc.c
bf185c60ec32704d850c39313abc089c56b18d44
[mirror_spl.git] / module / spl / spl-proc.c
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
27 #include <sys/proc.h>
28
29 #ifdef DEBUG_SUBSYSTEM
30 #undef DEBUG_SUBSYSTEM
31 #endif
32
33 #define DEBUG_SUBSYSTEM S_PROC
34
35 #ifdef DEBUG_KMEM
36 static unsigned long table_min = 0;
37 static unsigned long table_max = ~0;
38 #endif
39
40 #ifdef CONFIG_SYSCTL
41 static struct ctl_table_header *spl_header = NULL;
42 #endif /* CONFIG_SYSCTL */
43
44 #if defined(DEBUG_MUTEX) || defined(DEBUG_KMEM) || defined(DEBUG_KSTAT)
45 static struct proc_dir_entry *proc_spl = NULL;
46 #ifdef DEBUG_MUTEX
47 static struct proc_dir_entry *proc_spl_mutex = NULL;
48 static struct proc_dir_entry *proc_spl_mutex_stats = NULL;
49 #endif /* DEBUG_MUTEX */
50 #ifdef DEBUG_KMEM
51 static struct proc_dir_entry *proc_spl_kmem = NULL;
52 static struct proc_dir_entry *proc_spl_kmem_slab = NULL;
53 #endif /* DEBUG_KMEM */
54 #ifdef DEBUG_KSTAT
55 struct proc_dir_entry *proc_spl_kstat = NULL;
56 #endif /* DEBUG_KSTAT */
57 #endif /* DEBUG_MUTEX || DEBUG_KMEM || DEBUG_KSTAT */
58
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
102 #define CTL_SPL 0x87
103 #define CTL_SPL_DEBUG 0x88
104 #define CTL_SPL_MUTEX 0x89
105 #define CTL_SPL_KMEM 0x90
106 #define CTL_SPL_KSTAT 0x91
107
108 enum {
109 CTL_VERSION = 1, /* Version */
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 */
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 */
123 CTL_DEBUG_STACK_SIZE, /* Max observed stack size */
124
125 CTL_CONSOLE_RATELIMIT, /* Ratelimit console messages */
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 */
129
130 #ifdef DEBUG_KMEM
131 CTL_KMEM_KMEMUSED, /* Alloc'd kmem bytes */
132 CTL_KMEM_KMEMMAX, /* Max alloc'd by kmem bytes */
133 CTL_KMEM_VMEMUSED, /* Alloc'd vmem bytes */
134 CTL_KMEM_VMEMMAX, /* Max alloc'd by vmem bytes */
135 #endif
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 */
140 };
141 #endif /* HAVE_CTL_UNNUMBERED */
142
143 static int
144 proc_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
173 static int
174 proc_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
196 static int
197 proc_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
239 static int
240 proc_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
270 static int
271 proc_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) {
277 spl_debug_dumplog(0);
278 *ppos += *lenp;
279 } else {
280 *lenp = 0;
281 }
282
283 RETURN(0);
284 }
285
286 static int
287 proc_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) {
293 CERROR("Crashing due to forced SBUG\n");
294 SBUG();
295 /* Unreachable */
296 } else {
297 *lenp = 0;
298 }
299
300 RETURN(0);
301 }
302
303 static int
304 proc_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
337 static int
338 proc_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
371 static int
372 proc_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
400 #ifdef DEBUG_KMEM
401 static int
402 proc_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 = atomic64_read((atomic64_t *)table->data);
419 rc = proc_doulongvec_minmax(&dummy, write, filp,
420 buffer, lenp, ppos);
421 }
422
423 RETURN(rc);
424 }
425 #endif /* DEBUG_KMEM */
426
427 static int
428 proc_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;
432 int32_t val;
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
444 val = simple_strtol(str, &end, 16);
445 if (str == end)
446 RETURN(-EINVAL);
447
448 spl_hostid = (long)val;
449 (void)snprintf(hw_serial, 11, "%u", (val >= 0) ? val : -val);
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
467 #ifdef DEBUG_MUTEX
468 static void
469 mutex_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
476 static int
477 mutex_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
505 static void *
506 mutex_seq_start(struct seq_file *f, loff_t *pos)
507 {
508 struct list_head *p;
509 loff_t n = *pos;
510 ENTRY;
511
512 spin_lock(&mutex_stats_lock);
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
526 static void *
527 mutex_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
537 static void
538 mutex_seq_stop(struct seq_file *f, void *v)
539 {
540 spin_unlock(&mutex_stats_lock);
541 }
542
543 static 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
550 static int
551 proc_mutex_open(struct inode *inode, struct file *filp)
552 {
553 return seq_open(filp, &mutex_seq_ops);
554 }
555
556 static 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
564 #ifdef DEBUG_KMEM
565 static void
566 slab_seq_show_headers(struct seq_file *f)
567 {
568 seq_printf(f, "%-36s\n", "name");
569 }
570
571 static int
572 slab_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);
580 seq_printf(f, "%u %u %u - %lu %lu %lu - %lu %lu %lu - %lu %lu %lu\n",
581 (unsigned)skc->skc_obj_size,
582 (unsigned)skc->skc_slab_objs,
583 (unsigned)skc->skc_slab_size,
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,
592 (long unsigned)skc->skc_obj_max);
593
594 spin_unlock(&skc->skc_lock);
595
596 return 0;
597 }
598
599 static void *
600 slab_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
620 static void *
621 slab_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
631 static void
632 slab_seq_stop(struct seq_file *f, void *v)
633 {
634 up_read(&spl_kmem_cache_sem);
635 }
636
637 static 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
644 static int
645 proc_slab_open(struct inode *inode, struct file *filp)
646 {
647 return seq_open(filp, &slab_seq_ops);
648 }
649
650 static 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
658 static struct ctl_table spl_debug_table[] = {
659 {
660 .ctl_name = CTL_DEBUG_SUBSYS,
661 .procname = "subsystem",
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,
669 .procname = "mask",
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,
677 .procname = "printk",
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,
685 .procname = "mb",
686 .mode = 0644,
687 .proc_handler = &proc_debug_mb,
688 },
689 {
690 .ctl_name = CTL_DEBUG_BINARY,
691 .procname = "binary",
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,
715 .procname = "path",
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,
723 .procname = "dump",
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 {
762 .ctl_name = CTL_DEBUG_STACK_SIZE,
763 .procname = "stack_max",
764 .data = &spl_debug_stack,
765 .maxlen = sizeof(int),
766 .mode = 0444,
767 .proc_handler = &proc_dointvec,
768 },
769 {0},
770 };
771
772 #ifdef DEBUG_MUTEX
773 static 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
794 #ifdef DEBUG_KMEM
795 static struct ctl_table spl_kmem_table[] = {
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 },
832 {0},
833 };
834 #endif /* DEBUG_KMEM */
835
836 #ifdef DEBUG_KSTAT
837 static struct ctl_table spl_kstat_table[] = {
838 {0},
839 };
840 #endif /* DEBUG_KSTAT */
841
842 static 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 },
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",
865 .data = hw_serial,
866 .maxlen = sizeof(hw_serial),
867 .mode = 0444,
868 .proc_handler = &proc_dostring,
869 },
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 },
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 },
899 #endif
900 { 0 },
901 };
902
903 static struct ctl_table spl_dir[] = {
904 {
905 .ctl_name = CTL_SPL,
906 .procname = "spl",
907 .mode = 0555,
908 .child = spl_table,
909 },
910 { 0 }
911 };
912
913 static struct ctl_table spl_root[] = {
914 {
915 .ctl_name = CTL_KERN,
916 .procname = "kernel",
917 .mode = 0555,
918 .child = spl_dir,
919 },
920 { 0 }
921 };
922
923 static int
924 proc_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
932 struct proc_dir_entry *
933 proc_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
944 int
945 proc_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
956 int
957 proc_init(void)
958 {
959 int rc = 0;
960 ENTRY;
961
962 #ifdef CONFIG_SYSCTL
963 spl_header = spl_register_sysctl_table(spl_root, 0);
964 if (spl_header == NULL)
965 RETURN(-EUNATCH);
966 #endif /* CONFIG_SYSCTL */
967
968 #if defined(DEBUG_MUTEX) || defined(DEBUG_KMEM) || defined(DEBUG_KSTAT)
969 proc_spl = proc_mkdir("spl", NULL);
970 if (proc_spl == NULL)
971 GOTO(out, rc = -EUNATCH);
972
973 #ifdef DEBUG_MUTEX
974 proc_spl_mutex = proc_mkdir("mutex", proc_spl);
975 if (proc_spl_mutex == NULL)
976 GOTO(out, rc = -EUNATCH);
977
978 proc_spl_mutex_stats = create_proc_entry("stats_per", 0444,
979 proc_spl_mutex);
980 if (proc_spl_mutex_stats == NULL)
981 GOTO(out, rc = -EUNATCH);
982
983 proc_spl_mutex_stats->proc_fops = &proc_mutex_operations;
984 #endif /* DEBUG_MUTEX */
985
986 #ifdef DEBUG_KMEM
987 proc_spl_kmem = proc_mkdir("kmem", proc_spl);
988 if (proc_spl_kmem == NULL)
989 GOTO(out, rc = -EUNATCH);
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;
996 #endif /* DEBUG_KMEM */
997
998 #ifdef DEBUG_KSTAT
999 proc_spl_kstat = proc_mkdir("kstat", proc_spl);
1000 if (proc_spl_kstat == NULL)
1001 GOTO(out, rc = -EUNATCH);
1002 #endif /* DEBUG_KSTAT */
1003
1004 out:
1005 if (rc) {
1006 remove_proc_entry("kstat", proc_spl);
1007 #ifdef DEBUG_KMEM
1008 remove_proc_entry("slab", proc_spl_kmem);
1009 #endif
1010 remove_proc_entry("kmem", proc_spl);
1011 #ifdef DEBUG_MUTEX
1012 remove_proc_entry("stats_per", proc_spl_mutex);
1013 #endif
1014 remove_proc_entry("mutex", proc_spl);
1015 remove_proc_entry("spl", NULL);
1016 #ifdef CONFIG_SYSCTL
1017 spl_unregister_sysctl_table(spl_header);
1018 #endif /* CONFIG_SYSCTL */
1019 }
1020 #endif /* DEBUG_MUTEX || DEBUG_KMEM || DEBUG_KSTAT */
1021
1022 RETURN(rc);
1023 }
1024
1025 void
1026 proc_fini(void)
1027 {
1028 ENTRY;
1029
1030 #if defined(DEBUG_MUTEX) || defined(DEBUG_KMEM) || defined(DEBUG_KSTAT)
1031 remove_proc_entry("kstat", proc_spl);
1032 #ifdef DEBUG_KMEM
1033 remove_proc_entry("slab", proc_spl_kmem);
1034 #endif
1035 remove_proc_entry("kmem", proc_spl);
1036 #ifdef DEBUG_MUTEX
1037 remove_proc_entry("stats_per", proc_spl_mutex);
1038 #endif
1039 remove_proc_entry("mutex", proc_spl);
1040 remove_proc_entry("spl", NULL);
1041 #endif /* DEBUG_MUTEX || DEBUG_KMEM || DEBUG_KSTAT */
1042
1043 #ifdef CONFIG_SYSCTL
1044 ASSERT(spl_header != NULL);
1045 spl_unregister_sysctl_table(spl_header);
1046 #endif /* CONFIG_SYSCTL */
1047
1048 EXIT;
1049 }