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