]> git.proxmox.com Git - mirror_spl-debian.git/blob - module/spl/spl-proc.c
Merge branch 'kallsyms'
[mirror_spl-debian.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_VM CTL_UNNUMBERED
64 #define CTL_SPL_MUTEX CTL_UNNUMBERED
65 #define CTL_SPL_KMEM CTL_UNNUMBERED
66 #define CTL_SPL_KSTAT CTL_UNNUMBERED
67
68 #define CTL_VERSION CTL_UNNUMBERED /* Version */
69 #define CTL_HOSTID CTL_UNNUMBERED /* Host id by /usr/bin/hostid */
70 #define CTL_HW_SERIAL CTL_UNNUMBERED /* HW serial number by hostid */
71 #define CTL_KALLSYMS CTL_UNNUMBERED /* kallsyms_lookup_name addr */
72
73 #define CTL_DEBUG_SUBSYS CTL_UNNUMBERED /* Debug subsystem */
74 #define CTL_DEBUG_MASK CTL_UNNUMBERED /* Debug mask */
75 #define CTL_DEBUG_PRINTK CTL_UNNUMBERED /* All messages to console */
76 #define CTL_DEBUG_MB CTL_UNNUMBERED /* Debug buffer size */
77 #define CTL_DEBUG_BINARY CTL_UNNUMBERED /* Binary data in buffer */
78 #define CTL_DEBUG_CATASTROPHE CTL_UNNUMBERED /* Set if BUG'd or panic'd */
79 #define CTL_DEBUG_PANIC_ON_BUG CTL_UNNUMBERED /* Should panic on BUG */
80 #define CTL_DEBUG_PATH CTL_UNNUMBERED /* Dump log location */
81 #define CTL_DEBUG_DUMP CTL_UNNUMBERED /* Dump debug buffer to file */
82 #define CTL_DEBUG_FORCE_BUG CTL_UNNUMBERED /* Hook to force a BUG */
83 #define CTL_DEBUG_STACK_SIZE CTL_UNNUMBERED /* Max observed stack size */
84
85 #define CTL_CONSOLE_RATELIMIT CTL_UNNUMBERED /* Ratelimit console messages */
86 #define CTL_CONSOLE_MAX_DELAY_CS CTL_UNNUMBERED /* Max delay skip messages */
87 #define CTL_CONSOLE_MIN_DELAY_CS CTL_UNNUMBERED /* Init delay skip messages */
88 #define CTL_CONSOLE_BACKOFF CTL_UNNUMBERED /* Delay increase factor */
89
90 #define CTL_VM_MINFREE CTL_UNNUMBERED /* Minimum free memory */
91 #define CTL_VM_DESFREE CTL_UNNUMBERED /* Desired free memory */
92 #define CTL_VM_LOTSFREE CTL_UNNUMBERED /* Lots of free memory */
93 #define CTL_VM_NEEDFREE CTL_UNNUMBERED /* Need free memory */
94 #define CTL_VM_SWAPFS_MINFREE CTL_UNNUMBERED /* Minimum swapfs memory */
95 #define CTL_VM_SWAPFS_RESERVE CTL_UNNUMBERED /* Reserved swapfs memory */
96 #define CTL_VM_AVAILRMEM CTL_UNNUMBERED /* Easily available memory */
97 #define CTL_VM_FREEMEM CTL_UNNUMBERED /* Free memory */
98 #define CTL_VM_PHYSMEM CTL_UNNUMBERED /* Total physical memory */
99
100 #ifdef DEBUG_KMEM
101 #define CTL_KMEM_KMEMUSED CTL_UNNUMBERED /* Alloc'd kmem bytes */
102 #define CTL_KMEM_KMEMMAX CTL_UNNUMBERED /* Max alloc'd by kmem bytes */
103 #define CTL_KMEM_VMEMUSED CTL_UNNUMBERED /* Alloc'd vmem bytes */
104 #define CTL_KMEM_VMEMMAX CTL_UNNUMBERED /* Max alloc'd by vmem bytes */
105 #define CTL_KMEM_ALLOC_FAILED CTL_UNNUMBERED /* Cache allocations failed */
106 #endif
107
108 #define CTL_MUTEX_STATS CTL_UNNUMBERED /* Global mutex statistics */
109 #define CTL_MUTEX_STATS_PER CTL_UNNUMBERED /* Per mutex statistics */
110 #define CTL_MUTEX_SPIN_MAX CTL_UNNUMBERED /* Max mutex spin iterations */
111
112 #else /* HAVE_CTL_UNNUMBERED */
113
114 enum {
115 CTL_SPL = 0x87,
116 CTL_SPL_DEBUG = 0x88,
117 CTL_SPL_VM = 0x89,
118 CTL_SPL_MUTEX = 0x90,
119 CTL_SPL_KMEM = 0x91,
120 CTL_SPL_KSTAT = 0x92,
121 };
122
123 enum {
124 CTL_VERSION = 1, /* Version */
125 CTL_HOSTID, /* Host id reported by /usr/bin/hostid */
126 CTL_HW_SERIAL, /* Hardware serial number from hostid */
127 CTL_KALLSYMS, /* Address of kallsyms_lookup_name */
128
129 CTL_DEBUG_SUBSYS, /* Debug subsystem */
130 CTL_DEBUG_MASK, /* Debug mask */
131 CTL_DEBUG_PRINTK, /* Force all messages to console */
132 CTL_DEBUG_MB, /* Debug buffer size */
133 CTL_DEBUG_BINARY, /* Include binary data in buffer */
134 CTL_DEBUG_CATASTROPHE, /* Set if we have BUG'd or panic'd */
135 CTL_DEBUG_PANIC_ON_BUG, /* Set if we should panic on BUG */
136 CTL_DEBUG_PATH, /* Dump log location */
137 CTL_DEBUG_DUMP, /* Dump debug buffer to file */
138 CTL_DEBUG_FORCE_BUG, /* Hook to force a BUG */
139 CTL_DEBUG_STACK_SIZE, /* Max observed stack size */
140
141 CTL_CONSOLE_RATELIMIT, /* Ratelimit console messages */
142 CTL_CONSOLE_MAX_DELAY_CS, /* Max delay which we skip messages */
143 CTL_CONSOLE_MIN_DELAY_CS, /* Init delay which we skip messages */
144 CTL_CONSOLE_BACKOFF, /* Delay increase factor */
145
146 CTL_VM_MINFREE, /* Minimum free memory threshold */
147 CTL_VM_DESFREE, /* Desired free memory threshold */
148 CTL_VM_LOTSFREE, /* Lots of free memory threshold */
149 CTL_VM_NEEDFREE, /* Need free memory deficit */
150 CTL_VM_SWAPFS_MINFREE, /* Minimum swapfs memory */
151 CTL_VM_SWAPFS_RESERVE, /* Reserved swapfs memory */
152 CTL_VM_AVAILRMEM, /* Easily available memory */
153 CTL_VM_FREEMEM, /* Free memory */
154 CTL_VM_PHYSMEM, /* Total physical memory */
155
156 #ifdef DEBUG_KMEM
157 CTL_KMEM_KMEMUSED, /* Alloc'd kmem bytes */
158 CTL_KMEM_KMEMMAX, /* Max alloc'd by kmem bytes */
159 CTL_KMEM_VMEMUSED, /* Alloc'd vmem bytes */
160 CTL_KMEM_VMEMMAX, /* Max alloc'd by vmem bytes */
161 #endif
162
163 CTL_MUTEX_STATS, /* Global mutex statistics */
164 CTL_MUTEX_STATS_PER, /* Per mutex statistics */
165 CTL_MUTEX_SPIN_MAX, /* Maximum mutex spin iterations */
166 };
167 #endif /* HAVE_CTL_UNNUMBERED */
168
169 static int
170 proc_copyin_string(char *kbuffer, int kbuffer_size,
171 const char *ubuffer, int ubuffer_size)
172 {
173 int size;
174
175 if (ubuffer_size > kbuffer_size)
176 return -EOVERFLOW;
177
178 if (copy_from_user((void *)kbuffer, (void *)ubuffer, ubuffer_size))
179 return -EFAULT;
180
181 /* strip trailing whitespace */
182 size = strnlen(kbuffer, ubuffer_size);
183 while (size-- >= 0)
184 if (!isspace(kbuffer[size]))
185 break;
186
187 /* empty string */
188 if (size < 0)
189 return -EINVAL;
190
191 /* no space to terminate */
192 if (size == kbuffer_size)
193 return -EOVERFLOW;
194
195 kbuffer[size + 1] = 0;
196 return 0;
197 }
198
199 static int
200 proc_copyout_string(char *ubuffer, int ubuffer_size,
201 const char *kbuffer, char *append)
202 {
203 /* NB if 'append' != NULL, it's a single character to append to the
204 * copied out string - usually "\n", for /proc entries and
205 * (i.e. a terminating zero byte) for sysctl entries
206 */
207 int size = MIN(strlen(kbuffer), ubuffer_size);
208
209 if (copy_to_user(ubuffer, kbuffer, size))
210 return -EFAULT;
211
212 if (append != NULL && size < ubuffer_size) {
213 if (copy_to_user(ubuffer + size, append, 1))
214 return -EFAULT;
215
216 size++;
217 }
218
219 return size;
220 }
221
222 static int
223 proc_dobitmasks(struct ctl_table *table, int write, struct file *filp,
224 void __user *buffer, size_t *lenp, loff_t *ppos)
225 {
226 unsigned long *mask = table->data;
227 int is_subsys = (mask == &spl_debug_subsys) ? 1 : 0;
228 int is_printk = (mask == &spl_debug_printk) ? 1 : 0;
229 int size = 512, rc;
230 char *str;
231 ENTRY;
232
233 str = kmem_alloc(size, KM_SLEEP);
234 if (str == NULL)
235 RETURN(-ENOMEM);
236
237 if (write) {
238 rc = proc_copyin_string(str, size, buffer, *lenp);
239 if (rc < 0)
240 RETURN(rc);
241
242 rc = spl_debug_str2mask(mask, str, is_subsys);
243 /* Always print BUG/ASSERT to console, so keep this mask */
244 if (is_printk)
245 *mask |= D_EMERG;
246
247 *ppos += *lenp;
248 } else {
249 rc = spl_debug_mask2str(str, size, *mask, is_subsys);
250 if (*ppos >= rc)
251 rc = 0;
252 else
253 rc = proc_copyout_string(buffer, *lenp,
254 str + *ppos, "\n");
255 if (rc >= 0) {
256 *lenp = rc;
257 *ppos += rc;
258 }
259 }
260
261 kmem_free(str, size);
262 RETURN(rc);
263 }
264
265 static int
266 proc_debug_mb(struct ctl_table *table, int write, struct file *filp,
267 void __user *buffer, size_t *lenp, loff_t *ppos)
268 {
269 char str[32];
270 int rc, len;
271 ENTRY;
272
273 if (write) {
274 rc = proc_copyin_string(str, sizeof(str), buffer, *lenp);
275 if (rc < 0)
276 RETURN(rc);
277
278 rc = spl_debug_set_mb(simple_strtoul(str, NULL, 0));
279 *ppos += *lenp;
280 } else {
281 len = snprintf(str, sizeof(str), "%d", spl_debug_get_mb());
282 if (*ppos >= len)
283 rc = 0;
284 else
285 rc = proc_copyout_string(buffer, *lenp, str + *ppos, "\n");
286
287 if (rc >= 0) {
288 *lenp = rc;
289 *ppos += rc;
290 }
291 }
292
293 RETURN(rc);
294 }
295
296 static int
297 proc_dump_kernel(struct ctl_table *table, int write, struct file *filp,
298 void __user *buffer, size_t *lenp, loff_t *ppos)
299 {
300 ENTRY;
301
302 if (write) {
303 spl_debug_dumplog(0);
304 *ppos += *lenp;
305 } else {
306 *lenp = 0;
307 }
308
309 RETURN(0);
310 }
311
312 static int
313 proc_force_bug(struct ctl_table *table, int write, struct file *filp,
314 void __user *buffer, size_t *lenp, loff_t *ppos)
315 {
316 ENTRY;
317
318 if (write) {
319 CERROR("Crashing due to forced SBUG\n");
320 SBUG();
321 /* Unreachable */
322 } else {
323 *lenp = 0;
324 }
325
326 RETURN(0);
327 }
328
329 static int
330 proc_console_max_delay_cs(struct ctl_table *table, int write, struct file *filp,
331 void __user *buffer, size_t *lenp, loff_t *ppos)
332 {
333 int rc, max_delay_cs;
334 struct ctl_table dummy = *table;
335 long d;
336 ENTRY;
337
338 dummy.data = &max_delay_cs;
339 dummy.proc_handler = &proc_dointvec;
340
341 if (write) {
342 max_delay_cs = 0;
343 rc = proc_dointvec(&dummy, write, filp, buffer, lenp, ppos);
344 if (rc < 0)
345 RETURN(rc);
346
347 if (max_delay_cs <= 0)
348 RETURN(-EINVAL);
349
350 d = (max_delay_cs * HZ) / 100;
351 if (d == 0 || d < spl_console_min_delay)
352 RETURN(-EINVAL);
353
354 spl_console_max_delay = d;
355 } else {
356 max_delay_cs = (spl_console_max_delay * 100) / HZ;
357 rc = proc_dointvec(&dummy, write, filp, buffer, lenp, ppos);
358 }
359
360 RETURN(rc);
361 }
362
363 static int
364 proc_console_min_delay_cs(struct ctl_table *table, int write, struct file *filp,
365 void __user *buffer, size_t *lenp, loff_t *ppos)
366 {
367 int rc, min_delay_cs;
368 struct ctl_table dummy = *table;
369 long d;
370 ENTRY;
371
372 dummy.data = &min_delay_cs;
373 dummy.proc_handler = &proc_dointvec;
374
375 if (write) {
376 min_delay_cs = 0;
377 rc = proc_dointvec(&dummy, write, filp, buffer, lenp, ppos);
378 if (rc < 0)
379 RETURN(rc);
380
381 if (min_delay_cs <= 0)
382 RETURN(-EINVAL);
383
384 d = (min_delay_cs * HZ) / 100;
385 if (d == 0 || d > spl_console_max_delay)
386 RETURN(-EINVAL);
387
388 spl_console_min_delay = d;
389 } else {
390 min_delay_cs = (spl_console_min_delay * 100) / HZ;
391 rc = proc_dointvec(&dummy, write, filp, buffer, lenp, ppos);
392 }
393
394 RETURN(rc);
395 }
396
397 static int
398 proc_console_backoff(struct ctl_table *table, int write, struct file *filp,
399 void __user *buffer, size_t *lenp, loff_t *ppos)
400 {
401 int rc, backoff;
402 struct ctl_table dummy = *table;
403 ENTRY;
404
405 dummy.data = &backoff;
406 dummy.proc_handler = &proc_dointvec;
407
408 if (write) {
409 backoff = 0;
410 rc = proc_dointvec(&dummy, write, filp, buffer, lenp, ppos);
411 if (rc < 0)
412 RETURN(rc);
413
414 if (backoff <= 0)
415 RETURN(-EINVAL);
416
417 spl_console_backoff = backoff;
418 } else {
419 backoff = spl_console_backoff;
420 rc = proc_dointvec(&dummy, write, filp, buffer, lenp, ppos);
421 }
422
423 RETURN(rc);
424 }
425
426 #ifdef DEBUG_KMEM
427 static int
428 proc_doatomic64(struct ctl_table *table, int write, struct file *filp,
429 void __user *buffer, size_t *lenp, loff_t *ppos)
430 {
431 int rc = 0;
432 unsigned long min = 0, max = ~0, val;
433 struct ctl_table dummy = *table;
434 ENTRY;
435
436 dummy.data = &val;
437 dummy.proc_handler = &proc_dointvec;
438 dummy.extra1 = &min;
439 dummy.extra2 = &max;
440
441 if (write) {
442 *ppos += *lenp;
443 } else {
444 val = atomic64_read((atomic64_t *)table->data);
445 rc = proc_doulongvec_minmax(&dummy, write, filp,
446 buffer, lenp, ppos);
447 }
448
449 RETURN(rc);
450 }
451 #endif /* DEBUG_KMEM */
452
453 static int
454 proc_dohostid(struct ctl_table *table, int write, struct file *filp,
455 void __user *buffer, size_t *lenp, loff_t *ppos)
456 {
457 int len, rc = 0;
458 int32_t val;
459 char *end, str[32];
460 ENTRY;
461
462 if (write) {
463 /* We can't use proc_doulongvec_minmax() in the write
464 * case hear because hostid while a hex value has no
465 * leading 0x which confuses the helper function. */
466 rc = proc_copyin_string(str, sizeof(str), buffer, *lenp);
467 if (rc < 0)
468 RETURN(rc);
469
470 val = simple_strtol(str, &end, 16);
471 if (str == end)
472 RETURN(-EINVAL);
473
474 spl_hostid = (long)val;
475 (void)snprintf(hw_serial, HW_HOSTID_LEN-1, "%u",
476 (val >= 0) ? val : -val);
477 *ppos += *lenp;
478 } else {
479 len = snprintf(str, sizeof(str), "%lx", spl_hostid);
480 if (*ppos >= len)
481 rc = 0;
482 else
483 rc = proc_copyout_string(buffer, *lenp, str + *ppos, "\n");
484
485 if (rc >= 0) {
486 *lenp = rc;
487 *ppos += rc;
488 }
489 }
490
491 RETURN(rc);
492 }
493
494 #ifndef HAVE_KALLSYMS_LOOKUP_NAME
495 static int
496 proc_dokallsyms_lookup_name(struct ctl_table *table, int write,
497 struct file *filp, void __user *buffer,
498 size_t *lenp, loff_t *ppos) {
499 int len, rc = 0;
500 char *end, str[32];
501 ENTRY;
502
503 if (write) {
504 /* This may only be set once at module load time */
505 if (spl_kallsyms_lookup_name_fn)
506 RETURN(-EEXIST);
507
508 /* We can't use proc_doulongvec_minmax() in the write
509 * case hear because the address while a hex value has no
510 * leading 0x which confuses the helper function. */
511 rc = proc_copyin_string(str, sizeof(str), buffer, *lenp);
512 if (rc < 0)
513 RETURN(rc);
514
515 spl_kallsyms_lookup_name_fn =
516 (kallsyms_lookup_name_t)simple_strtoul(str, &end, 16);
517 if (str == end)
518 RETURN(-EINVAL);
519
520 *ppos += *lenp;
521 } else {
522 len = snprintf(str, sizeof(str), "%lx",
523 (unsigned long)spl_kallsyms_lookup_name_fn);
524 if (*ppos >= len)
525 rc = 0;
526 else
527 rc = proc_copyout_string(buffer,*lenp,str+*ppos,"\n");
528
529 if (rc >= 0) {
530 *lenp = rc;
531 *ppos += rc;
532 }
533 }
534
535 RETURN(rc);
536 }
537 #endif /* HAVE_KALLSYMS_LOOKUP_NAME */
538
539 static int
540 proc_doavailrmem(struct ctl_table *table, int write, struct file *filp,
541 void __user *buffer, size_t *lenp, loff_t *ppos)
542 {
543 int len, rc = 0;
544 char str[32];
545 ENTRY;
546
547 if (write) {
548 *ppos += *lenp;
549 } else {
550 len = snprintf(str, sizeof(str), "%lu", (unsigned long)availrmem);
551 if (*ppos >= len)
552 rc = 0;
553 else
554 rc = proc_copyout_string(buffer, *lenp, str + *ppos, "\n");
555
556 if (rc >= 0) {
557 *lenp = rc;
558 *ppos += rc;
559 }
560 }
561
562 RETURN(rc);
563 }
564
565 static int
566 proc_dofreemem(struct ctl_table *table, int write, struct file *filp,
567 void __user *buffer, size_t *lenp, loff_t *ppos)
568 {
569 int len, rc = 0;
570 char str[32];
571 ENTRY;
572
573 if (write) {
574 *ppos += *lenp;
575 } else {
576 len = snprintf(str, sizeof(str), "%lu", (unsigned long)freemem);
577 if (*ppos >= len)
578 rc = 0;
579 else
580 rc = proc_copyout_string(buffer, *lenp, str + *ppos, "\n");
581
582 if (rc >= 0) {
583 *lenp = rc;
584 *ppos += rc;
585 }
586 }
587
588 RETURN(rc);
589 }
590
591 #ifdef DEBUG_MUTEX
592 static void
593 mutex_seq_show_headers(struct seq_file *f)
594 {
595 seq_printf(f, "%-36s %-4s %-16s\t"
596 "e_tot\te_nh\te_sp\te_sl\tte_tot\tte_nh\n",
597 "name", "type", "owner");
598 }
599
600 static int
601 mutex_seq_show(struct seq_file *f, void *p)
602 {
603 kmutex_t *mp = p;
604 char t = 'X';
605 int i;
606
607 ASSERT(mp->km_magic == KM_MAGIC);
608
609 switch (mp->km_type) {
610 case MUTEX_DEFAULT: t = 'D'; break;
611 case MUTEX_SPIN: t = 'S'; break;
612 case MUTEX_ADAPTIVE: t = 'A'; break;
613 default:
614 SBUG();
615 }
616 seq_printf(f, "%-36s %c ", mp->km_name, t);
617 if (mp->km_owner)
618 seq_printf(f, "%p\t", mp->km_owner);
619 else
620 seq_printf(f, "%-16s\t", "<not held>");
621
622 for (i = 0; i < MUTEX_STATS_SIZE; i++)
623 seq_printf(f, "%d%c", mp->km_stats[i],
624 (i + 1 == MUTEX_STATS_SIZE) ? '\n' : '\t');
625
626 return 0;
627 }
628
629 static void *
630 mutex_seq_start(struct seq_file *f, loff_t *pos)
631 {
632 struct list_head *p;
633 loff_t n = *pos;
634 ENTRY;
635
636 spin_lock(&mutex_stats_lock);
637 if (!n)
638 mutex_seq_show_headers(f);
639
640 p = mutex_stats_list.next;
641 while (n--) {
642 p = p->next;
643 if (p == &mutex_stats_list)
644 RETURN(NULL);
645 }
646
647 RETURN(list_entry(p, kmutex_t, km_list));
648 }
649
650 static void *
651 mutex_seq_next(struct seq_file *f, void *p, loff_t *pos)
652 {
653 kmutex_t *mp = p;
654 ENTRY;
655
656 ++*pos;
657 RETURN((mp->km_list.next == &mutex_stats_list) ?
658 NULL : list_entry(mp->km_list.next, kmutex_t, km_list));
659 }
660
661 static void
662 mutex_seq_stop(struct seq_file *f, void *v)
663 {
664 spin_unlock(&mutex_stats_lock);
665 }
666
667 static struct seq_operations mutex_seq_ops = {
668 .show = mutex_seq_show,
669 .start = mutex_seq_start,
670 .next = mutex_seq_next,
671 .stop = mutex_seq_stop,
672 };
673
674 static int
675 proc_mutex_open(struct inode *inode, struct file *filp)
676 {
677 return seq_open(filp, &mutex_seq_ops);
678 }
679
680 static struct file_operations proc_mutex_operations = {
681 .open = proc_mutex_open,
682 .read = seq_read,
683 .llseek = seq_lseek,
684 .release = seq_release,
685 };
686 #endif /* DEBUG_MUTEX */
687
688 #ifdef DEBUG_KMEM
689 static void
690 slab_seq_show_headers(struct seq_file *f)
691 {
692 seq_printf(f, "%-36s\n", "name");
693 }
694
695 static int
696 slab_seq_show(struct seq_file *f, void *p)
697 {
698 spl_kmem_cache_t *skc = p;
699
700 ASSERT(skc->skc_magic == SKC_MAGIC);
701
702 spin_lock(&skc->skc_lock);
703 seq_printf(f, "%-36s ", skc->skc_name);
704 seq_printf(f, "%u %u %u - %lu %lu %lu - %lu %lu %lu - %lu %lu %lu\n",
705 (unsigned)skc->skc_obj_size,
706 (unsigned)skc->skc_slab_objs,
707 (unsigned)skc->skc_slab_size,
708 (long unsigned)skc->skc_slab_fail,
709 (long unsigned)skc->skc_slab_create,
710 (long unsigned)skc->skc_slab_destroy,
711 (long unsigned)skc->skc_slab_total,
712 (long unsigned)skc->skc_slab_alloc,
713 (long unsigned)skc->skc_slab_max,
714 (long unsigned)skc->skc_obj_total,
715 (long unsigned)skc->skc_obj_alloc,
716 (long unsigned)skc->skc_obj_max);
717
718 spin_unlock(&skc->skc_lock);
719
720 return 0;
721 }
722
723 static void *
724 slab_seq_start(struct seq_file *f, loff_t *pos)
725 {
726 struct list_head *p;
727 loff_t n = *pos;
728 ENTRY;
729
730 down_read(&spl_kmem_cache_sem);
731 if (!n)
732 slab_seq_show_headers(f);
733
734 p = spl_kmem_cache_list.next;
735 while (n--) {
736 p = p->next;
737 if (p == &spl_kmem_cache_list)
738 RETURN(NULL);
739 }
740
741 RETURN(list_entry(p, spl_kmem_cache_t, skc_list));
742 }
743
744 static void *
745 slab_seq_next(struct seq_file *f, void *p, loff_t *pos)
746 {
747 spl_kmem_cache_t *skc = p;
748 ENTRY;
749
750 ++*pos;
751 RETURN((skc->skc_list.next == &spl_kmem_cache_list) ?
752 NULL : list_entry(skc->skc_list.next, spl_kmem_cache_t, skc_list));
753 }
754
755 static void
756 slab_seq_stop(struct seq_file *f, void *v)
757 {
758 up_read(&spl_kmem_cache_sem);
759 }
760
761 static struct seq_operations slab_seq_ops = {
762 .show = slab_seq_show,
763 .start = slab_seq_start,
764 .next = slab_seq_next,
765 .stop = slab_seq_stop,
766 };
767
768 static int
769 proc_slab_open(struct inode *inode, struct file *filp)
770 {
771 return seq_open(filp, &slab_seq_ops);
772 }
773
774 static struct file_operations proc_slab_operations = {
775 .open = proc_slab_open,
776 .read = seq_read,
777 .llseek = seq_lseek,
778 .release = seq_release,
779 };
780 #endif /* DEBUG_KMEM */
781
782 static struct ctl_table spl_debug_table[] = {
783 {
784 .ctl_name = CTL_DEBUG_SUBSYS,
785 .procname = "subsystem",
786 .data = &spl_debug_subsys,
787 .maxlen = sizeof(unsigned long),
788 .mode = 0644,
789 .proc_handler = &proc_dobitmasks
790 },
791 {
792 .ctl_name = CTL_DEBUG_MASK,
793 .procname = "mask",
794 .data = &spl_debug_mask,
795 .maxlen = sizeof(unsigned long),
796 .mode = 0644,
797 .proc_handler = &proc_dobitmasks
798 },
799 {
800 .ctl_name = CTL_DEBUG_PRINTK,
801 .procname = "printk",
802 .data = &spl_debug_printk,
803 .maxlen = sizeof(unsigned long),
804 .mode = 0644,
805 .proc_handler = &proc_dobitmasks
806 },
807 {
808 .ctl_name = CTL_DEBUG_MB,
809 .procname = "mb",
810 .mode = 0644,
811 .proc_handler = &proc_debug_mb,
812 },
813 {
814 .ctl_name = CTL_DEBUG_BINARY,
815 .procname = "binary",
816 .data = &spl_debug_binary,
817 .maxlen = sizeof(int),
818 .mode = 0644,
819 .proc_handler = &proc_dointvec,
820 },
821 {
822 .ctl_name = CTL_DEBUG_CATASTROPHE,
823 .procname = "catastrophe",
824 .data = &spl_debug_catastrophe,
825 .maxlen = sizeof(int),
826 .mode = 0444,
827 .proc_handler = &proc_dointvec,
828 },
829 {
830 .ctl_name = CTL_DEBUG_PANIC_ON_BUG,
831 .procname = "panic_on_bug",
832 .data = &spl_debug_panic_on_bug,
833 .maxlen = sizeof(int),
834 .mode = 0644,
835 .proc_handler = &proc_dointvec
836 },
837 {
838 .ctl_name = CTL_DEBUG_PATH,
839 .procname = "path",
840 .data = spl_debug_file_path,
841 .maxlen = sizeof(spl_debug_file_path),
842 .mode = 0644,
843 .proc_handler = &proc_dostring,
844 },
845 {
846 .ctl_name = CTL_DEBUG_DUMP,
847 .procname = "dump",
848 .mode = 0200,
849 .proc_handler = &proc_dump_kernel,
850 },
851 { .ctl_name = CTL_DEBUG_FORCE_BUG,
852 .procname = "force_bug",
853 .mode = 0200,
854 .proc_handler = &proc_force_bug,
855 },
856 {
857 .ctl_name = CTL_CONSOLE_RATELIMIT,
858 .procname = "console_ratelimit",
859 .data = &spl_console_ratelimit,
860 .maxlen = sizeof(int),
861 .mode = 0644,
862 .proc_handler = &proc_dointvec,
863 },
864 {
865 .ctl_name = CTL_CONSOLE_MAX_DELAY_CS,
866 .procname = "console_max_delay_centisecs",
867 .maxlen = sizeof(int),
868 .mode = 0644,
869 .proc_handler = &proc_console_max_delay_cs,
870 },
871 {
872 .ctl_name = CTL_CONSOLE_MIN_DELAY_CS,
873 .procname = "console_min_delay_centisecs",
874 .maxlen = sizeof(int),
875 .mode = 0644,
876 .proc_handler = &proc_console_min_delay_cs,
877 },
878 {
879 .ctl_name = CTL_CONSOLE_BACKOFF,
880 .procname = "console_backoff",
881 .maxlen = sizeof(int),
882 .mode = 0644,
883 .proc_handler = &proc_console_backoff,
884 },
885 {
886 .ctl_name = CTL_DEBUG_STACK_SIZE,
887 .procname = "stack_max",
888 .data = &spl_debug_stack,
889 .maxlen = sizeof(int),
890 .mode = 0444,
891 .proc_handler = &proc_dointvec,
892 },
893 {0},
894 };
895
896 static struct ctl_table spl_vm_table[] = {
897 {
898 .ctl_name = CTL_VM_MINFREE,
899 .procname = "minfree",
900 .data = &minfree,
901 .maxlen = sizeof(int),
902 .mode = 0644,
903 .proc_handler = &proc_dointvec,
904 },
905 {
906 .ctl_name = CTL_VM_DESFREE,
907 .procname = "desfree",
908 .data = &desfree,
909 .maxlen = sizeof(int),
910 .mode = 0644,
911 .proc_handler = &proc_dointvec,
912 },
913 {
914 .ctl_name = CTL_VM_LOTSFREE,
915 .procname = "lotsfree",
916 .data = &lotsfree,
917 .maxlen = sizeof(int),
918 .mode = 0644,
919 .proc_handler = &proc_dointvec,
920 },
921 {
922 .ctl_name = CTL_VM_NEEDFREE,
923 .procname = "needfree",
924 .data = &needfree,
925 .maxlen = sizeof(int),
926 .mode = 0444,
927 .proc_handler = &proc_dointvec,
928 },
929 {
930 .ctl_name = CTL_VM_SWAPFS_MINFREE,
931 .procname = "swapfs_minfree",
932 .data = &swapfs_minfree,
933 .maxlen = sizeof(int),
934 .mode = 0644,
935 .proc_handler = &proc_dointvec,
936 },
937 {
938 .ctl_name = CTL_VM_SWAPFS_RESERVE,
939 .procname = "swapfs_reserve",
940 .data = &swapfs_reserve,
941 .maxlen = sizeof(int),
942 .mode = 0644,
943 .proc_handler = &proc_dointvec,
944 },
945 {
946 .ctl_name = CTL_VM_AVAILRMEM,
947 .procname = "availrmem",
948 .mode = 0444,
949 .proc_handler = &proc_doavailrmem,
950 },
951 {
952 .ctl_name = CTL_VM_FREEMEM,
953 .procname = "freemem",
954 .data = (void *)2,
955 .maxlen = sizeof(int),
956 .mode = 0444,
957 .proc_handler = &proc_dofreemem,
958 },
959 {
960 .ctl_name = CTL_VM_PHYSMEM,
961 .procname = "physmem",
962 .data = &physmem,
963 .maxlen = sizeof(int),
964 .mode = 0444,
965 .proc_handler = &proc_dointvec,
966 },
967 {0},
968 };
969
970 #ifdef DEBUG_MUTEX
971 static struct ctl_table spl_mutex_table[] = {
972 {
973 .ctl_name = CTL_MUTEX_STATS,
974 .procname = "stats",
975 .data = &mutex_stats,
976 .maxlen = sizeof(int) * MUTEX_STATS_SIZE,
977 .mode = 0444,
978 .proc_handler = &proc_dointvec,
979 },
980 {
981 .ctl_name = CTL_MUTEX_SPIN_MAX,
982 .procname = "spin_max",
983 .data = &mutex_spin_max,
984 .maxlen = sizeof(int),
985 .mode = 0644,
986 .proc_handler = &proc_dointvec,
987 },
988 {0},
989 };
990 #endif /* DEBUG_MUTEX */
991
992 #ifdef DEBUG_KMEM
993 static struct ctl_table spl_kmem_table[] = {
994 {
995 .ctl_name = CTL_KMEM_KMEMUSED,
996 .procname = "kmem_used",
997 .data = &kmem_alloc_used,
998 .maxlen = sizeof(atomic64_t),
999 .mode = 0444,
1000 .proc_handler = &proc_doatomic64,
1001 },
1002 {
1003 .ctl_name = CTL_KMEM_KMEMMAX,
1004 .procname = "kmem_max",
1005 .data = &kmem_alloc_max,
1006 .maxlen = sizeof(unsigned long),
1007 .extra1 = &table_min,
1008 .extra2 = &table_max,
1009 .mode = 0444,
1010 .proc_handler = &proc_doulongvec_minmax,
1011 },
1012 {
1013 .ctl_name = CTL_KMEM_VMEMUSED,
1014 .procname = "vmem_used",
1015 .data = &vmem_alloc_used,
1016 .maxlen = sizeof(atomic64_t),
1017 .mode = 0444,
1018 .proc_handler = &proc_doatomic64,
1019 },
1020 {
1021 .ctl_name = CTL_KMEM_VMEMMAX,
1022 .procname = "vmem_max",
1023 .data = &vmem_alloc_max,
1024 .maxlen = sizeof(unsigned long),
1025 .extra1 = &table_min,
1026 .extra2 = &table_max,
1027 .mode = 0444,
1028 .proc_handler = &proc_doulongvec_minmax,
1029 },
1030 {0},
1031 };
1032 #endif /* DEBUG_KMEM */
1033
1034 #ifdef DEBUG_KSTAT
1035 static struct ctl_table spl_kstat_table[] = {
1036 {0},
1037 };
1038 #endif /* DEBUG_KSTAT */
1039
1040 static struct ctl_table spl_table[] = {
1041 /* NB No .strategy entries have been provided since
1042 * sysctl(8) prefers to go via /proc for portability.
1043 */
1044 {
1045 .ctl_name = CTL_VERSION,
1046 .procname = "version",
1047 .data = spl_version,
1048 .maxlen = sizeof(spl_version),
1049 .mode = 0444,
1050 .proc_handler = &proc_dostring,
1051 },
1052 {
1053 .ctl_name = CTL_HOSTID,
1054 .procname = "hostid",
1055 .data = &spl_hostid,
1056 .maxlen = sizeof(unsigned long),
1057 .mode = 0644,
1058 .proc_handler = &proc_dohostid,
1059 },
1060 {
1061 .ctl_name = CTL_HW_SERIAL,
1062 .procname = "hw_serial",
1063 .data = hw_serial,
1064 .maxlen = sizeof(hw_serial),
1065 .mode = 0444,
1066 .proc_handler = &proc_dostring,
1067 },
1068 #ifndef HAVE_KALLSYMS_LOOKUP_NAME
1069 {
1070 .ctl_name = CTL_KALLSYMS,
1071 .procname = "kallsyms_lookup_name",
1072 .data = &spl_kallsyms_lookup_name_fn,
1073 .maxlen = sizeof(unsigned long),
1074 .mode = 0644,
1075 .proc_handler = &proc_dokallsyms_lookup_name,
1076 },
1077 #endif
1078 {
1079 .ctl_name = CTL_SPL_DEBUG,
1080 .procname = "debug",
1081 .mode = 0555,
1082 .child = spl_debug_table,
1083 },
1084 {
1085 .ctl_name = CTL_SPL_VM,
1086 .procname = "vm",
1087 .mode = 0555,
1088 .child = spl_vm_table,
1089 },
1090 #ifdef DEBUG_MUTEX
1091 {
1092 .ctl_name = CTL_SPL_MUTEX,
1093 .procname = "mutex",
1094 .mode = 0555,
1095 .child = spl_mutex_table,
1096 },
1097 #endif
1098 #ifdef DEBUG_KMEM
1099 {
1100 .ctl_name = CTL_SPL_KMEM,
1101 .procname = "kmem",
1102 .mode = 0555,
1103 .child = spl_kmem_table,
1104 },
1105 #endif
1106 #ifdef DEBUG_KSTAT
1107 {
1108 .ctl_name = CTL_SPL_KSTAT,
1109 .procname = "kstat",
1110 .mode = 0555,
1111 .child = spl_kstat_table,
1112 },
1113 #endif
1114 { 0 },
1115 };
1116
1117 static struct ctl_table spl_dir[] = {
1118 {
1119 .ctl_name = CTL_SPL,
1120 .procname = "spl",
1121 .mode = 0555,
1122 .child = spl_table,
1123 },
1124 { 0 }
1125 };
1126
1127 static struct ctl_table spl_root[] = {
1128 {
1129 .ctl_name = CTL_KERN,
1130 .procname = "kernel",
1131 .mode = 0555,
1132 .child = spl_dir,
1133 },
1134 { 0 }
1135 };
1136
1137 static int
1138 proc_dir_entry_match(int len, const char *name, struct proc_dir_entry *de)
1139 {
1140 if (de->namelen != len)
1141 return 0;
1142
1143 return !memcmp(name, de->name, len);
1144 }
1145
1146 struct proc_dir_entry *
1147 proc_dir_entry_find(struct proc_dir_entry *root, const char *str)
1148 {
1149 struct proc_dir_entry *de;
1150
1151 for (de = root->subdir; de; de = de->next)
1152 if (proc_dir_entry_match(strlen(str), str, de))
1153 return de;
1154
1155 return NULL;
1156 }
1157
1158 int
1159 proc_dir_entries(struct proc_dir_entry *root)
1160 {
1161 struct proc_dir_entry *de;
1162 int i = 0;
1163
1164 for (de = root->subdir; de; de = de->next)
1165 i++;
1166
1167 return i;
1168 }
1169
1170 int
1171 proc_init(void)
1172 {
1173 int rc = 0;
1174 ENTRY;
1175
1176 #ifdef CONFIG_SYSCTL
1177 spl_header = spl_register_sysctl_table(spl_root, 0);
1178 if (spl_header == NULL)
1179 RETURN(-EUNATCH);
1180 #endif /* CONFIG_SYSCTL */
1181
1182 #if defined(DEBUG_MUTEX) || defined(DEBUG_KMEM) || defined(DEBUG_KSTAT)
1183 proc_spl = proc_mkdir("spl", NULL);
1184 if (proc_spl == NULL)
1185 GOTO(out, rc = -EUNATCH);
1186
1187 #ifdef DEBUG_MUTEX
1188 proc_spl_mutex = proc_mkdir("mutex", proc_spl);
1189 if (proc_spl_mutex == NULL)
1190 GOTO(out, rc = -EUNATCH);
1191
1192 proc_spl_mutex_stats = create_proc_entry("stats_per", 0444,
1193 proc_spl_mutex);
1194 if (proc_spl_mutex_stats == NULL)
1195 GOTO(out, rc = -EUNATCH);
1196
1197 proc_spl_mutex_stats->proc_fops = &proc_mutex_operations;
1198 #endif /* DEBUG_MUTEX */
1199
1200 #ifdef DEBUG_KMEM
1201 proc_spl_kmem = proc_mkdir("kmem", proc_spl);
1202 if (proc_spl_kmem == NULL)
1203 GOTO(out, rc = -EUNATCH);
1204
1205 proc_spl_kmem_slab = create_proc_entry("slab", 0444, proc_spl_kmem);
1206 if (proc_spl_kmem_slab == NULL)
1207 GOTO(out, rc = -EUNATCH);
1208
1209 proc_spl_kmem_slab->proc_fops = &proc_slab_operations;
1210 #endif /* DEBUG_KMEM */
1211
1212 #ifdef DEBUG_KSTAT
1213 proc_spl_kstat = proc_mkdir("kstat", proc_spl);
1214 if (proc_spl_kstat == NULL)
1215 GOTO(out, rc = -EUNATCH);
1216 #endif /* DEBUG_KSTAT */
1217
1218 out:
1219 if (rc) {
1220 remove_proc_entry("kstat", proc_spl);
1221 #ifdef DEBUG_KMEM
1222 remove_proc_entry("slab", proc_spl_kmem);
1223 #endif
1224 remove_proc_entry("kmem", proc_spl);
1225 #ifdef DEBUG_MUTEX
1226 remove_proc_entry("stats_per", proc_spl_mutex);
1227 #endif
1228 remove_proc_entry("mutex", proc_spl);
1229 remove_proc_entry("spl", NULL);
1230 #ifdef CONFIG_SYSCTL
1231 spl_unregister_sysctl_table(spl_header);
1232 #endif /* CONFIG_SYSCTL */
1233 }
1234 #endif /* DEBUG_MUTEX || DEBUG_KMEM || DEBUG_KSTAT */
1235
1236 RETURN(rc);
1237 }
1238
1239 void
1240 proc_fini(void)
1241 {
1242 ENTRY;
1243
1244 #if defined(DEBUG_MUTEX) || defined(DEBUG_KMEM) || defined(DEBUG_KSTAT)
1245 remove_proc_entry("kstat", proc_spl);
1246 #ifdef DEBUG_KMEM
1247 remove_proc_entry("slab", proc_spl_kmem);
1248 #endif
1249 remove_proc_entry("kmem", proc_spl);
1250 #ifdef DEBUG_MUTEX
1251 remove_proc_entry("stats_per", proc_spl_mutex);
1252 #endif
1253 remove_proc_entry("mutex", proc_spl);
1254 remove_proc_entry("spl", NULL);
1255 #endif /* DEBUG_MUTEX || DEBUG_KMEM || DEBUG_KSTAT */
1256
1257 #ifdef CONFIG_SYSCTL
1258 ASSERT(spl_header != NULL);
1259 spl_unregister_sysctl_table(spl_header);
1260 #endif /* CONFIG_SYSCTL */
1261
1262 EXIT;
1263 }