]> git.proxmox.com Git - mirror_spl.git/blob - modules/spl/spl-proc.c
Fixes:
[mirror_spl.git] / modules / 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 #endif /* DEBUG_KMEM */
53 #ifdef DEBUG_KSTAT
54 struct proc_dir_entry *proc_spl_kstat = NULL;
55 #endif /* DEBUG_KSTAT */
56 #endif /* DEBUG_MUTEX || DEBUG_KMEM || DEBUG_KSTAT */
57
58 #ifdef HAVE_CTL_UNNUMBERED
59
60 #define CTL_SPL CTL_UNNUMBERED
61 #define CTL_SPL_DEBUG CTL_UNNUMBERED
62 #define CTL_SPL_MUTEX CTL_UNNUMBERED
63 #define CTL_SPL_KMEM CTL_UNNUMBERED
64 #define CTL_SPL_KSTAT CTL_UNNUMBERED
65
66 #define CTL_VERSION CTL_UNNUMBERED /* Version */
67 #define CTL_HOSTID CTL_UNNUMBERED /* Host id by /usr/bin/hostid */
68 #define CTL_HW_SERIAL CTL_UNNUMBERED /* HW serial number by hostid */
69
70 #define CTL_DEBUG_SUBSYS CTL_UNNUMBERED /* Debug subsystem */
71 #define CTL_DEBUG_MASK CTL_UNNUMBERED /* Debug mask */
72 #define CTL_DEBUG_PRINTK CTL_UNNUMBERED /* All messages to console */
73 #define CTL_DEBUG_MB CTL_UNNUMBERED /* Debug buffer size */
74 #define CTL_DEBUG_BINARY CTL_UNNUMBERED /* Binary data in buffer */
75 #define CTL_DEBUG_CATASTROPHE CTL_UNNUMBERED /* Set if BUG'd or panic'd */
76 #define CTL_DEBUG_PANIC_ON_BUG CTL_UNNUMBERED /* Should panic on BUG */
77 #define CTL_DEBUG_PATH CTL_UNNUMBERED /* Dump log location */
78 #define CTL_DEBUG_DUMP CTL_UNNUMBERED /* Dump debug buffer to file */
79 #define CTL_DEBUG_FORCE_BUG CTL_UNNUMBERED /* Hook to force a BUG */
80 #define CTL_DEBUG_STACK_SIZE CTL_UNNUMBERED /* Max observed stack size */
81
82 #define CTL_CONSOLE_RATELIMIT CTL_UNNUMBERED /* Ratelimit console messages */
83 #define CTL_CONSOLE_MAX_DELAY_CS CTL_UNNUMBERED /* Max delay skip messages */
84 #define CTL_CONSOLE_MIN_DELAY_CS CTL_UNNUMBERED /* Init delay skip messages */
85 #define CTL_CONSOLE_BACKOFF CTL_UNNUMBERED /* Delay increase factor */
86
87 #ifdef DEBUG_KMEM
88 #define CTL_KMEM_KMEMUSED CTL_UNNUMBERED /* Alloc'd kmem bytes */
89 #define CTL_KMEM_KMEMMAX CTL_UNNUMBERED /* Max alloc'd by kmem bytes */
90 #define CTL_KMEM_VMEMUSED CTL_UNNUMBERED /* Alloc'd vmem bytes */
91 #define CTL_KMEM_VMEMMAX CTL_UNNUMBERED /* Max alloc'd by vmem bytes */
92 #define CTL_KMEM_ALLOC_FAILED CTL_UNNUMBERED /* Cache allocations failed */
93 #endif
94
95 #define CTL_MUTEX_STATS CTL_UNNUMBERED /* Global mutex statistics */
96 #define CTL_MUTEX_STATS_PER CTL_UNNUMBERED /* Per mutex statistics */
97 #define CTL_MUTEX_SPIN_MAX CTL_UNNUMBERED /* Max mutex spin iterations */
98
99 #else /* HAVE_CTL_UNNUMBERED */
100
101 #define CTL_SPL 0x87
102 #define CTL_SPL_DEBUG 0x88
103 #define CTL_SPL_MUTEX 0x89
104 #define CTL_SPL_KMEM 0x90
105 #define CTL_SPL_KSTAT 0x91
106
107 enum {
108 CTL_VERSION = 1, /* Version */
109 CTL_HOSTID, /* Host id reported by /usr/bin/hostid */
110 CTL_HW_SERIAL, /* Hardware serial number from hostid */
111
112 CTL_DEBUG_SUBSYS, /* Debug subsystem */
113 CTL_DEBUG_MASK, /* Debug mask */
114 CTL_DEBUG_PRINTK, /* Force all messages to console */
115 CTL_DEBUG_MB, /* Debug buffer size */
116 CTL_DEBUG_BINARY, /* Include binary data in buffer */
117 CTL_DEBUG_CATASTROPHE, /* Set if we have BUG'd or panic'd */
118 CTL_DEBUG_PANIC_ON_BUG, /* Set if we should panic on BUG */
119 CTL_DEBUG_PATH, /* Dump log location */
120 CTL_DEBUG_DUMP, /* Dump debug buffer to file */
121 CTL_DEBUG_FORCE_BUG, /* Hook to force a BUG */
122 CTL_DEBUG_STACK_SIZE, /* Max observed stack size */
123
124 CTL_CONSOLE_RATELIMIT, /* Ratelimit console messages */
125 CTL_CONSOLE_MAX_DELAY_CS, /* Max delay at which we skip messages */
126 CTL_CONSOLE_MIN_DELAY_CS, /* Init delay at which we skip messages */
127 CTL_CONSOLE_BACKOFF, /* Delay increase factor */
128
129 #ifdef DEBUG_KMEM
130 CTL_KMEM_KMEMUSED, /* Alloc'd kmem bytes */
131 CTL_KMEM_KMEMMAX, /* Max alloc'd by kmem bytes */
132 CTL_KMEM_VMEMUSED, /* Alloc'd vmem bytes */
133 CTL_KMEM_VMEMMAX, /* Max alloc'd by vmem bytes */
134 CTL_KMEM_ALLOC_FAILED, /* Cache allocation failed */
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 = atomic_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 sprintf(hw_serial, "%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 static struct ctl_table spl_debug_table[] = {
565 {
566 .ctl_name = CTL_DEBUG_SUBSYS,
567 .procname = "subsystem",
568 .data = &spl_debug_subsys,
569 .maxlen = sizeof(unsigned long),
570 .mode = 0644,
571 .proc_handler = &proc_dobitmasks
572 },
573 {
574 .ctl_name = CTL_DEBUG_MASK,
575 .procname = "mask",
576 .data = &spl_debug_mask,
577 .maxlen = sizeof(unsigned long),
578 .mode = 0644,
579 .proc_handler = &proc_dobitmasks
580 },
581 {
582 .ctl_name = CTL_DEBUG_PRINTK,
583 .procname = "printk",
584 .data = &spl_debug_printk,
585 .maxlen = sizeof(unsigned long),
586 .mode = 0644,
587 .proc_handler = &proc_dobitmasks
588 },
589 {
590 .ctl_name = CTL_DEBUG_MB,
591 .procname = "mb",
592 .mode = 0644,
593 .proc_handler = &proc_debug_mb,
594 },
595 {
596 .ctl_name = CTL_DEBUG_BINARY,
597 .procname = "binary",
598 .data = &spl_debug_binary,
599 .maxlen = sizeof(int),
600 .mode = 0644,
601 .proc_handler = &proc_dointvec,
602 },
603 {
604 .ctl_name = CTL_DEBUG_CATASTROPHE,
605 .procname = "catastrophe",
606 .data = &spl_debug_catastrophe,
607 .maxlen = sizeof(int),
608 .mode = 0444,
609 .proc_handler = &proc_dointvec,
610 },
611 {
612 .ctl_name = CTL_DEBUG_PANIC_ON_BUG,
613 .procname = "panic_on_bug",
614 .data = &spl_debug_panic_on_bug,
615 .maxlen = sizeof(int),
616 .mode = 0644,
617 .proc_handler = &proc_dointvec
618 },
619 {
620 .ctl_name = CTL_DEBUG_PATH,
621 .procname = "path",
622 .data = spl_debug_file_path,
623 .maxlen = sizeof(spl_debug_file_path),
624 .mode = 0644,
625 .proc_handler = &proc_dostring,
626 },
627 {
628 .ctl_name = CTL_DEBUG_DUMP,
629 .procname = "dump",
630 .mode = 0200,
631 .proc_handler = &proc_dump_kernel,
632 },
633 { .ctl_name = CTL_DEBUG_FORCE_BUG,
634 .procname = "force_bug",
635 .mode = 0200,
636 .proc_handler = &proc_force_bug,
637 },
638 {
639 .ctl_name = CTL_CONSOLE_RATELIMIT,
640 .procname = "console_ratelimit",
641 .data = &spl_console_ratelimit,
642 .maxlen = sizeof(int),
643 .mode = 0644,
644 .proc_handler = &proc_dointvec,
645 },
646 {
647 .ctl_name = CTL_CONSOLE_MAX_DELAY_CS,
648 .procname = "console_max_delay_centisecs",
649 .maxlen = sizeof(int),
650 .mode = 0644,
651 .proc_handler = &proc_console_max_delay_cs,
652 },
653 {
654 .ctl_name = CTL_CONSOLE_MIN_DELAY_CS,
655 .procname = "console_min_delay_centisecs",
656 .maxlen = sizeof(int),
657 .mode = 0644,
658 .proc_handler = &proc_console_min_delay_cs,
659 },
660 {
661 .ctl_name = CTL_CONSOLE_BACKOFF,
662 .procname = "console_backoff",
663 .maxlen = sizeof(int),
664 .mode = 0644,
665 .proc_handler = &proc_console_backoff,
666 },
667 {
668 .ctl_name = CTL_DEBUG_STACK_SIZE,
669 .procname = "stack_max",
670 .data = &spl_debug_stack,
671 .maxlen = sizeof(int),
672 .mode = 0444,
673 .proc_handler = &proc_dointvec,
674 },
675 {0},
676 };
677
678 #ifdef DEBUG_MUTEX
679 static struct ctl_table spl_mutex_table[] = {
680 {
681 .ctl_name = CTL_MUTEX_STATS,
682 .procname = "stats",
683 .data = &mutex_stats,
684 .maxlen = sizeof(int) * MUTEX_STATS_SIZE,
685 .mode = 0444,
686 .proc_handler = &proc_dointvec,
687 },
688 {
689 .ctl_name = CTL_MUTEX_SPIN_MAX,
690 .procname = "spin_max",
691 .data = &mutex_spin_max,
692 .maxlen = sizeof(int),
693 .mode = 0644,
694 .proc_handler = &proc_dointvec,
695 },
696 {0},
697 };
698 #endif /* DEBUG_MUTEX */
699
700 #ifdef DEBUG_KMEM
701 static struct ctl_table spl_kmem_table[] = {
702 {
703 .ctl_name = CTL_KMEM_KMEMUSED,
704 .procname = "kmem_used",
705 .data = &kmem_alloc_used,
706 .maxlen = sizeof(atomic64_t),
707 .mode = 0444,
708 .proc_handler = &proc_doatomic64,
709 },
710 {
711 .ctl_name = CTL_KMEM_KMEMMAX,
712 .procname = "kmem_max",
713 .data = &kmem_alloc_max,
714 .maxlen = sizeof(unsigned long),
715 .extra1 = &table_min,
716 .extra2 = &table_max,
717 .mode = 0444,
718 .proc_handler = &proc_doulongvec_minmax,
719 },
720 {
721 .ctl_name = CTL_KMEM_VMEMUSED,
722 .procname = "vmem_used",
723 .data = &vmem_alloc_used,
724 .maxlen = sizeof(atomic64_t),
725 .mode = 0444,
726 .proc_handler = &proc_doatomic64,
727 },
728 {
729 .ctl_name = CTL_KMEM_VMEMMAX,
730 .procname = "vmem_max",
731 .data = &vmem_alloc_max,
732 .maxlen = sizeof(unsigned long),
733 .extra1 = &table_min,
734 .extra2 = &table_max,
735 .mode = 0444,
736 .proc_handler = &proc_doulongvec_minmax,
737 },
738 {
739 .ctl_name = CTL_KMEM_ALLOC_FAILED,
740 .procname = "kmem_alloc_failed",
741 .data = &kmem_cache_alloc_failed,
742 .maxlen = sizeof(atomic64_t),
743 .mode = 0444,
744 .proc_handler = &proc_doatomic64,
745 },
746 {0},
747 };
748 #endif /* DEBUG_KMEM */
749
750 #ifdef DEBUG_KSTAT
751 static struct ctl_table spl_kstat_table[] = {
752 {0},
753 };
754 #endif /* DEBUG_KSTAT */
755
756 static struct ctl_table spl_table[] = {
757 /* NB No .strategy entries have been provided since
758 * sysctl(8) prefers to go via /proc for portability.
759 */
760 {
761 .ctl_name = CTL_VERSION,
762 .procname = "version",
763 .data = spl_version,
764 .maxlen = sizeof(spl_version),
765 .mode = 0444,
766 .proc_handler = &proc_dostring,
767 },
768 {
769 .ctl_name = CTL_HOSTID,
770 .procname = "hostid",
771 .data = &spl_hostid,
772 .maxlen = sizeof(unsigned long),
773 .mode = 0644,
774 .proc_handler = &proc_dohostid,
775 },
776 {
777 .ctl_name = CTL_HW_SERIAL,
778 .procname = "hw_serial",
779 .data = hw_serial,
780 .maxlen = sizeof(hw_serial),
781 .mode = 0444,
782 .proc_handler = &proc_dostring,
783 },
784 {
785 .ctl_name = CTL_SPL_DEBUG,
786 .procname = "debug",
787 .mode = 0555,
788 .child = spl_debug_table,
789 },
790 #ifdef DEBUG_MUTEX
791 {
792 .ctl_name = CTL_SPL_MUTEX,
793 .procname = "mutex",
794 .mode = 0555,
795 .child = spl_mutex_table,
796 },
797 #endif
798 #ifdef DEBUG_KMEM
799 {
800 .ctl_name = CTL_SPL_KMEM,
801 .procname = "kmem",
802 .mode = 0555,
803 .child = spl_kmem_table,
804 },
805 #endif
806 #ifdef DEBUG_KSTAT
807 {
808 .ctl_name = CTL_SPL_KSTAT,
809 .procname = "kstat",
810 .mode = 0555,
811 .child = spl_kstat_table,
812 },
813 #endif
814 { 0 },
815 };
816
817 static struct ctl_table spl_dir[] = {
818 {
819 .ctl_name = CTL_SPL,
820 .procname = "spl",
821 .mode = 0555,
822 .child = spl_table,
823 },
824 { 0 }
825 };
826
827 static struct ctl_table spl_root[] = {
828 {
829 .ctl_name = CTL_KERN,
830 .procname = "kernel",
831 .mode = 0555,
832 .child = spl_dir,
833 },
834 { 0 }
835 };
836
837 static int
838 proc_dir_entry_match(int len, const char *name, struct proc_dir_entry *de)
839 {
840 if (de->namelen != len)
841 return 0;
842
843 return !memcmp(name, de->name, len);
844 }
845
846 struct proc_dir_entry *
847 proc_dir_entry_find(struct proc_dir_entry *root, const char *str)
848 {
849 struct proc_dir_entry *de;
850
851 for (de = root->subdir; de; de = de->next)
852 if (proc_dir_entry_match(strlen(str), str, de))
853 return de;
854
855 return NULL;
856 }
857
858 int
859 proc_dir_entries(struct proc_dir_entry *root)
860 {
861 struct proc_dir_entry *de;
862 int i = 0;
863
864 for (de = root->subdir; de; de = de->next)
865 i++;
866
867 return i;
868 }
869
870 int
871 proc_init(void)
872 {
873 int rc = 0;
874 ENTRY;
875
876 #ifdef CONFIG_SYSCTL
877 spl_header = spl_register_sysctl_table(spl_root, 0);
878 if (spl_header == NULL)
879 RETURN(-EUNATCH);
880 #endif /* CONFIG_SYSCTL */
881
882 #if defined(DEBUG_MUTEX) || defined(DEBUG_KMEM) || defined(DEBUG_KSTAT)
883 proc_spl = proc_mkdir("spl", NULL);
884 if (proc_spl == NULL)
885 GOTO(out, rc = -EUNATCH);
886
887 #ifdef DEBUG_MUTEX
888 proc_spl_mutex = proc_mkdir("mutex", proc_spl);
889 if (proc_spl_mutex == NULL)
890 GOTO(out, rc = -EUNATCH);
891
892 proc_spl_mutex_stats = create_proc_entry("stats_per", 0444,
893 proc_spl_mutex);
894 if (proc_spl_mutex_stats == NULL)
895 GOTO(out, rc = -EUNATCH);
896
897 proc_spl_mutex_stats->proc_fops = &proc_mutex_operations;
898 #endif /* DEBUG_MUTEX */
899
900 #ifdef DEBUG_KMEM
901 proc_spl_kmem = proc_mkdir("kmem", proc_spl);
902 if (proc_spl_kmem == NULL)
903 GOTO(out, rc = -EUNATCH);
904 #endif /* DEBUG_KMEM */
905
906 #ifdef DEBUG_KSTAT
907 proc_spl_kstat = proc_mkdir("kstat", proc_spl);
908 if (proc_spl_kstat == NULL)
909 GOTO(out, rc = -EUNATCH);
910 #endif /* DEBUG_KSTAT */
911
912 out:
913 if (rc) {
914 remove_proc_entry("kstat", proc_spl);
915 remove_proc_entry("kmem", proc_spl);
916 remove_proc_entry("stats_per", proc_spl_mutex);
917 remove_proc_entry("mutex", proc_spl);
918 #ifdef CONFIG_SYSCTL
919 spl_unregister_sysctl_table(spl_header);
920 #endif /* CONFIG_SYSCTL */
921 }
922 #endif /* DEBUG_MUTEX || DEBUG_KMEM || DEBUG_KSTAT */
923
924 RETURN(rc);
925 }
926
927 void
928 proc_fini(void)
929 {
930 ENTRY;
931
932 #if defined(DEBUG_MUTEX) || defined(DEBUG_KMEM) || defined(DEBUG_KSTAT)
933 remove_proc_entry("kstat", proc_spl);
934 remove_proc_entry("kmem", proc_spl);
935 remove_proc_entry("stats_per", proc_spl_mutex);
936 remove_proc_entry("mutex", proc_spl);
937 #endif /* DEBUG_MUTEX || DEBUG_KMEM || DEBUG_KSTAT */
938
939 #ifdef CONFIG_SYSCTL
940 ASSERT(spl_header != NULL);
941 spl_unregister_sysctl_table(spl_header);
942 #endif /* CONFIG_SYSCTL */
943
944 EXIT;
945 }