]> git.proxmox.com Git - mirror_spl-debian.git/blame - module/spl/spl-proc.c
Mutex tests updated to use task queues instead of work queues.
[mirror_spl-debian.git] / module / spl / spl-proc.c
CommitLineData
715f6251 1/*
2 * This file is part of the SPL: Solaris Porting Layer.
3 *
4 * Copyright (c) 2008 Lawrence Livermore National Security, LLC.
5 * Produced at Lawrence Livermore National Laboratory
6 * Written by:
7 * Brian Behlendorf <behlendorf1@llnl.gov>,
8 * Herb Wartens <wartens2@llnl.gov>,
9 * Jim Garlick <garlick@llnl.gov>
10 * UCRL-CODE-235197
11 *
12 * This is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This is distributed in the hope that it will be useful, but WITHOUT
18 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 * for more details.
21 *
22 * You should have received a copy of the GNU General Public License along
23 * with this program; if not, write to the Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 */
26
04a479f7 27#include <sys/proc.h>
57d1b188 28
29#ifdef DEBUG_SUBSYSTEM
30#undef DEBUG_SUBSYSTEM
31#endif
32
33#define DEBUG_SUBSYSTEM S_PROC
34
404992e3 35#ifdef DEBUG_KMEM
57d1b188 36static unsigned long table_min = 0;
37static unsigned long table_max = ~0;
404992e3 38#endif
39
40#ifdef CONFIG_SYSCTL
41static struct ctl_table_header *spl_header = NULL;
c30df9c8 42#endif /* CONFIG_SYSCTL */
43
57d86234 44#if defined(DEBUG_MUTEX) || defined(DEBUG_KMEM) || defined(DEBUG_KSTAT)
c30df9c8 45static struct proc_dir_entry *proc_spl = NULL;
404992e3 46#ifdef DEBUG_MUTEX
c30df9c8 47static struct proc_dir_entry *proc_spl_mutex = NULL;
48static struct proc_dir_entry *proc_spl_mutex_stats = NULL;
49#endif /* DEBUG_MUTEX */
04a479f7 50#ifdef DEBUG_KMEM
c30df9c8 51static struct proc_dir_entry *proc_spl_kmem = NULL;
ff449ac4 52static struct proc_dir_entry *proc_spl_kmem_slab = NULL;
c30df9c8 53#endif /* DEBUG_KMEM */
04a479f7 54#ifdef DEBUG_KSTAT
c30df9c8 55struct proc_dir_entry *proc_spl_kstat = NULL;
56#endif /* DEBUG_KSTAT */
57#endif /* DEBUG_MUTEX || DEBUG_KMEM || DEBUG_KSTAT */
57d1b188 58
57d86234 59#ifdef HAVE_CTL_UNNUMBERED
60
61#define CTL_SPL CTL_UNNUMBERED
62#define CTL_SPL_DEBUG CTL_UNNUMBERED
36b313da 63#define CTL_SPL_VM CTL_UNNUMBERED
57d86234 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 */
d1ff2312 71#define CTL_KALLSYMS CTL_UNNUMBERED /* kallsyms_lookup_name addr */
57d86234 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
36b313da
BB
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 */
36b313da 95#define CTL_VM_SWAPFS_RESERVE CTL_UNNUMBERED /* Reserved swapfs memory */
4ab13d3b
BB
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 */
36b313da 99
57d86234 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
36b313da
BB
114enum {
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};
9ab1ac14 122
57d1b188 123enum {
36b313da
BB
124 CTL_VERSION = 1, /* Version */
125 CTL_HOSTID, /* Host id reported by /usr/bin/hostid */
126 CTL_HW_SERIAL, /* Hardware serial number from hostid */
d1ff2312 127 CTL_KALLSYMS, /* Address of kallsyms_lookup_name */
36b313da
BB
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 */
36b313da 151 CTL_VM_SWAPFS_RESERVE, /* Reserved swapfs memory */
4ab13d3b
BB
152 CTL_VM_AVAILRMEM, /* Easily available memory */
153 CTL_VM_FREEMEM, /* Free memory */
154 CTL_VM_PHYSMEM, /* Total physical memory */
9ab1ac14 155
57d1b188 156#ifdef DEBUG_KMEM
36b313da
BB
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 */
57d1b188 161#endif
9ab1ac14 162
36b313da
BB
163 CTL_MUTEX_STATS, /* Global mutex statistics */
164 CTL_MUTEX_STATS_PER, /* Per mutex statistics */
165 CTL_MUTEX_SPIN_MAX, /* Maximum mutex spin iterations */
57d1b188 166};
57d86234 167#endif /* HAVE_CTL_UNNUMBERED */
57d1b188 168
169static int
170proc_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
199static int
200proc_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
222static int
223proc_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
265static int
266proc_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
296static int
297proc_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) {
7fea96c0 303 spl_debug_dumplog(0);
57d1b188 304 *ppos += *lenp;
305 } else {
306 *lenp = 0;
307 }
308
309 RETURN(0);
310}
311
312static int
313proc_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) {
2fae1b3d 319 CERROR("Crashing due to forced SBUG\n");
320 SBUG();
57d1b188 321 /* Unreachable */
322 } else {
323 *lenp = 0;
324 }
325
326 RETURN(0);
327}
328
329static int
330proc_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
363static int
364proc_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
397static int
398proc_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
c6dc93d6 426#ifdef DEBUG_KMEM
57d1b188 427static int
428proc_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 {
550f1705 444 val = atomic64_read((atomic64_t *)table->data);
57d1b188 445 rc = proc_doulongvec_minmax(&dummy, write, filp,
446 buffer, lenp, ppos);
447 }
448
449 RETURN(rc);
450}
c6dc93d6 451#endif /* DEBUG_KMEM */
57d1b188 452
453static int
454proc_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;
937879f1 458 int32_t val;
57d1b188 459 char *end, str[32];
a0b5ae8a 460 ENTRY;
57d1b188 461
462 if (write) {
a0b5ae8a
RC
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. */
57d1b188 466 rc = proc_copyin_string(str, sizeof(str), buffer, *lenp);
467 if (rc < 0)
468 RETURN(rc);
469
937879f1 470 val = simple_strtol(str, &end, 16);
a0b5ae8a
RC
471 if (str == end)
472 RETURN(-EINVAL);
57d1b188 473
a0b5ae8a
RC
474 spl_hostid = (long) val;
475 (void) snprintf(hw_serial, HW_HOSTID_LEN, "%u",
476 (val >= 0) ? val : -val);
477 hw_serial[HW_HOSTID_LEN - 1] = '\0';
57d1b188 478 *ppos += *lenp;
479 } else {
480 len = snprintf(str, sizeof(str), "%lx", spl_hostid);
481 if (*ppos >= len)
482 rc = 0;
483 else
484 rc = proc_copyout_string(buffer, *lenp, str + *ppos, "\n");
485
486 if (rc >= 0) {
487 *lenp = rc;
488 *ppos += rc;
489 }
490 }
491
492 RETURN(rc);
493}
494
d1ff2312
BB
495#ifndef HAVE_KALLSYMS_LOOKUP_NAME
496static int
497proc_dokallsyms_lookup_name(struct ctl_table *table, int write,
498 struct file *filp, void __user *buffer,
499 size_t *lenp, loff_t *ppos) {
500 int len, rc = 0;
501 char *end, str[32];
502 ENTRY;
503
504 if (write) {
505 /* This may only be set once at module load time */
506 if (spl_kallsyms_lookup_name_fn)
507 RETURN(-EEXIST);
508
509 /* We can't use proc_doulongvec_minmax() in the write
510 * case hear because the address while a hex value has no
511 * leading 0x which confuses the helper function. */
512 rc = proc_copyin_string(str, sizeof(str), buffer, *lenp);
513 if (rc < 0)
514 RETURN(rc);
515
516 spl_kallsyms_lookup_name_fn =
517 (kallsyms_lookup_name_t)simple_strtoul(str, &end, 16);
518 if (str == end)
519 RETURN(-EINVAL);
520
521 *ppos += *lenp;
522 } else {
523 len = snprintf(str, sizeof(str), "%lx",
524 (unsigned long)spl_kallsyms_lookup_name_fn);
525 if (*ppos >= len)
526 rc = 0;
527 else
528 rc = proc_copyout_string(buffer,*lenp,str+*ppos,"\n");
529
530 if (rc >= 0) {
531 *lenp = rc;
532 *ppos += rc;
533 }
534 }
535
536 RETURN(rc);
537}
538#endif /* HAVE_KALLSYMS_LOOKUP_NAME */
539
4ab13d3b
BB
540static int
541proc_doavailrmem(struct ctl_table *table, int write, struct file *filp,
542 void __user *buffer, size_t *lenp, loff_t *ppos)
543{
544 int len, rc = 0;
545 char str[32];
546 ENTRY;
547
548 if (write) {
549 *ppos += *lenp;
550 } else {
551 len = snprintf(str, sizeof(str), "%lu", (unsigned long)availrmem);
552 if (*ppos >= len)
553 rc = 0;
554 else
555 rc = proc_copyout_string(buffer, *lenp, str + *ppos, "\n");
556
557 if (rc >= 0) {
558 *lenp = rc;
559 *ppos += rc;
560 }
561 }
562
563 RETURN(rc);
564}
565
566static int
567proc_dofreemem(struct ctl_table *table, int write, struct file *filp,
568 void __user *buffer, size_t *lenp, loff_t *ppos)
569{
570 int len, rc = 0;
571 char str[32];
572 ENTRY;
573
574 if (write) {
575 *ppos += *lenp;
576 } else {
577 len = snprintf(str, sizeof(str), "%lu", (unsigned long)freemem);
578 if (*ppos >= len)
579 rc = 0;
580 else
581 rc = proc_copyout_string(buffer, *lenp, str + *ppos, "\n");
582
583 if (rc >= 0) {
584 *lenp = rc;
585 *ppos += rc;
586 }
587 }
588
589 RETURN(rc);
590}
591
9ab1ac14 592#ifdef DEBUG_MUTEX
593static void
594mutex_seq_show_headers(struct seq_file *f)
595{
596 seq_printf(f, "%-36s %-4s %-16s\t"
597 "e_tot\te_nh\te_sp\te_sl\tte_tot\tte_nh\n",
598 "name", "type", "owner");
599}
600
601static int
602mutex_seq_show(struct seq_file *f, void *p)
603{
604 kmutex_t *mp = p;
605 char t = 'X';
606 int i;
607
608 ASSERT(mp->km_magic == KM_MAGIC);
609
610 switch (mp->km_type) {
611 case MUTEX_DEFAULT: t = 'D'; break;
612 case MUTEX_SPIN: t = 'S'; break;
613 case MUTEX_ADAPTIVE: t = 'A'; break;
614 default:
615 SBUG();
616 }
617 seq_printf(f, "%-36s %c ", mp->km_name, t);
618 if (mp->km_owner)
619 seq_printf(f, "%p\t", mp->km_owner);
620 else
621 seq_printf(f, "%-16s\t", "<not held>");
622
623 for (i = 0; i < MUTEX_STATS_SIZE; i++)
624 seq_printf(f, "%d%c", mp->km_stats[i],
625 (i + 1 == MUTEX_STATS_SIZE) ? '\n' : '\t');
626
627 return 0;
628}
629
630static void *
631mutex_seq_start(struct seq_file *f, loff_t *pos)
632{
633 struct list_head *p;
634 loff_t n = *pos;
635 ENTRY;
636
404992e3 637 spin_lock(&mutex_stats_lock);
9ab1ac14 638 if (!n)
639 mutex_seq_show_headers(f);
640
641 p = mutex_stats_list.next;
642 while (n--) {
643 p = p->next;
644 if (p == &mutex_stats_list)
645 RETURN(NULL);
646 }
647
648 RETURN(list_entry(p, kmutex_t, km_list));
649}
650
651static void *
652mutex_seq_next(struct seq_file *f, void *p, loff_t *pos)
653{
654 kmutex_t *mp = p;
655 ENTRY;
656
657 ++*pos;
658 RETURN((mp->km_list.next == &mutex_stats_list) ?
659 NULL : list_entry(mp->km_list.next, kmutex_t, km_list));
660}
661
662static void
663mutex_seq_stop(struct seq_file *f, void *v)
664{
404992e3 665 spin_unlock(&mutex_stats_lock);
9ab1ac14 666}
667
668static struct seq_operations mutex_seq_ops = {
669 .show = mutex_seq_show,
670 .start = mutex_seq_start,
671 .next = mutex_seq_next,
672 .stop = mutex_seq_stop,
673};
674
675static int
676proc_mutex_open(struct inode *inode, struct file *filp)
677{
678 return seq_open(filp, &mutex_seq_ops);
679}
680
681static struct file_operations proc_mutex_operations = {
682 .open = proc_mutex_open,
683 .read = seq_read,
684 .llseek = seq_lseek,
685 .release = seq_release,
686};
687#endif /* DEBUG_MUTEX */
688
ff449ac4 689#ifdef DEBUG_KMEM
690static void
691slab_seq_show_headers(struct seq_file *f)
692{
693 seq_printf(f, "%-36s\n", "name");
694}
695
696static int
697slab_seq_show(struct seq_file *f, void *p)
698{
699 spl_kmem_cache_t *skc = p;
700
701 ASSERT(skc->skc_magic == SKC_MAGIC);
702
703 spin_lock(&skc->skc_lock);
704 seq_printf(f, "%-36s ", skc->skc_name);
a1502d76 705 seq_printf(f, "%u %u %u - %lu %lu %lu - %lu %lu %lu - %lu %lu %lu\n",
ff449ac4 706 (unsigned)skc->skc_obj_size,
a1502d76 707 (unsigned)skc->skc_slab_objs,
ff449ac4 708 (unsigned)skc->skc_slab_size,
ff449ac4 709 (long unsigned)skc->skc_slab_fail,
710 (long unsigned)skc->skc_slab_create,
711 (long unsigned)skc->skc_slab_destroy,
712 (long unsigned)skc->skc_slab_total,
713 (long unsigned)skc->skc_slab_alloc,
714 (long unsigned)skc->skc_slab_max,
715 (long unsigned)skc->skc_obj_total,
716 (long unsigned)skc->skc_obj_alloc,
a1502d76 717 (long unsigned)skc->skc_obj_max);
ff449ac4 718
719 spin_unlock(&skc->skc_lock);
720
721 return 0;
722}
723
724static void *
725slab_seq_start(struct seq_file *f, loff_t *pos)
726{
727 struct list_head *p;
728 loff_t n = *pos;
729 ENTRY;
730
731 down_read(&spl_kmem_cache_sem);
732 if (!n)
733 slab_seq_show_headers(f);
734
735 p = spl_kmem_cache_list.next;
736 while (n--) {
737 p = p->next;
738 if (p == &spl_kmem_cache_list)
739 RETURN(NULL);
740 }
741
742 RETURN(list_entry(p, spl_kmem_cache_t, skc_list));
743}
744
745static void *
746slab_seq_next(struct seq_file *f, void *p, loff_t *pos)
747{
748 spl_kmem_cache_t *skc = p;
749 ENTRY;
750
751 ++*pos;
752 RETURN((skc->skc_list.next == &spl_kmem_cache_list) ?
753 NULL : list_entry(skc->skc_list.next, spl_kmem_cache_t, skc_list));
754}
755
756static void
757slab_seq_stop(struct seq_file *f, void *v)
758{
759 up_read(&spl_kmem_cache_sem);
760}
761
762static struct seq_operations slab_seq_ops = {
763 .show = slab_seq_show,
764 .start = slab_seq_start,
765 .next = slab_seq_next,
766 .stop = slab_seq_stop,
767};
768
769static int
770proc_slab_open(struct inode *inode, struct file *filp)
771{
772 return seq_open(filp, &slab_seq_ops);
773}
774
775static struct file_operations proc_slab_operations = {
776 .open = proc_slab_open,
777 .read = seq_read,
778 .llseek = seq_lseek,
779 .release = seq_release,
780};
781#endif /* DEBUG_KMEM */
782
9ab1ac14 783static struct ctl_table spl_debug_table[] = {
57d1b188 784 {
785 .ctl_name = CTL_DEBUG_SUBSYS,
9ab1ac14 786 .procname = "subsystem",
57d1b188 787 .data = &spl_debug_subsys,
788 .maxlen = sizeof(unsigned long),
789 .mode = 0644,
790 .proc_handler = &proc_dobitmasks
791 },
792 {
793 .ctl_name = CTL_DEBUG_MASK,
9ab1ac14 794 .procname = "mask",
57d1b188 795 .data = &spl_debug_mask,
796 .maxlen = sizeof(unsigned long),
797 .mode = 0644,
798 .proc_handler = &proc_dobitmasks
799 },
800 {
801 .ctl_name = CTL_DEBUG_PRINTK,
9ab1ac14 802 .procname = "printk",
57d1b188 803 .data = &spl_debug_printk,
804 .maxlen = sizeof(unsigned long),
805 .mode = 0644,
806 .proc_handler = &proc_dobitmasks
807 },
808 {
809 .ctl_name = CTL_DEBUG_MB,
9ab1ac14 810 .procname = "mb",
57d1b188 811 .mode = 0644,
812 .proc_handler = &proc_debug_mb,
813 },
814 {
815 .ctl_name = CTL_DEBUG_BINARY,
9ab1ac14 816 .procname = "binary",
57d1b188 817 .data = &spl_debug_binary,
818 .maxlen = sizeof(int),
819 .mode = 0644,
820 .proc_handler = &proc_dointvec,
821 },
822 {
823 .ctl_name = CTL_DEBUG_CATASTROPHE,
824 .procname = "catastrophe",
825 .data = &spl_debug_catastrophe,
826 .maxlen = sizeof(int),
827 .mode = 0444,
828 .proc_handler = &proc_dointvec,
829 },
830 {
831 .ctl_name = CTL_DEBUG_PANIC_ON_BUG,
832 .procname = "panic_on_bug",
833 .data = &spl_debug_panic_on_bug,
834 .maxlen = sizeof(int),
835 .mode = 0644,
836 .proc_handler = &proc_dointvec
837 },
838 {
839 .ctl_name = CTL_DEBUG_PATH,
9ab1ac14 840 .procname = "path",
57d1b188 841 .data = spl_debug_file_path,
842 .maxlen = sizeof(spl_debug_file_path),
843 .mode = 0644,
844 .proc_handler = &proc_dostring,
845 },
846 {
847 .ctl_name = CTL_DEBUG_DUMP,
9ab1ac14 848 .procname = "dump",
57d1b188 849 .mode = 0200,
850 .proc_handler = &proc_dump_kernel,
851 },
852 { .ctl_name = CTL_DEBUG_FORCE_BUG,
853 .procname = "force_bug",
854 .mode = 0200,
855 .proc_handler = &proc_force_bug,
856 },
857 {
858 .ctl_name = CTL_CONSOLE_RATELIMIT,
859 .procname = "console_ratelimit",
860 .data = &spl_console_ratelimit,
861 .maxlen = sizeof(int),
862 .mode = 0644,
863 .proc_handler = &proc_dointvec,
864 },
865 {
866 .ctl_name = CTL_CONSOLE_MAX_DELAY_CS,
867 .procname = "console_max_delay_centisecs",
868 .maxlen = sizeof(int),
869 .mode = 0644,
870 .proc_handler = &proc_console_max_delay_cs,
871 },
872 {
873 .ctl_name = CTL_CONSOLE_MIN_DELAY_CS,
874 .procname = "console_min_delay_centisecs",
875 .maxlen = sizeof(int),
876 .mode = 0644,
877 .proc_handler = &proc_console_min_delay_cs,
878 },
879 {
880 .ctl_name = CTL_CONSOLE_BACKOFF,
881 .procname = "console_backoff",
882 .maxlen = sizeof(int),
883 .mode = 0644,
884 .proc_handler = &proc_console_backoff,
885 },
886 {
9ab1ac14 887 .ctl_name = CTL_DEBUG_STACK_SIZE,
57d1b188 888 .procname = "stack_max",
889 .data = &spl_debug_stack,
890 .maxlen = sizeof(int),
891 .mode = 0444,
892 .proc_handler = &proc_dointvec,
893 },
9ab1ac14 894 {0},
895};
896
36b313da
BB
897static struct ctl_table spl_vm_table[] = {
898 {
899 .ctl_name = CTL_VM_MINFREE,
900 .procname = "minfree",
901 .data = &minfree,
902 .maxlen = sizeof(int),
903 .mode = 0644,
904 .proc_handler = &proc_dointvec,
905 },
906 {
907 .ctl_name = CTL_VM_DESFREE,
908 .procname = "desfree",
909 .data = &desfree,
910 .maxlen = sizeof(int),
911 .mode = 0644,
912 .proc_handler = &proc_dointvec,
913 },
914 {
915 .ctl_name = CTL_VM_LOTSFREE,
916 .procname = "lotsfree",
917 .data = &lotsfree,
918 .maxlen = sizeof(int),
919 .mode = 0644,
920 .proc_handler = &proc_dointvec,
921 },
922 {
923 .ctl_name = CTL_VM_NEEDFREE,
924 .procname = "needfree",
925 .data = &needfree,
926 .maxlen = sizeof(int),
927 .mode = 0444,
928 .proc_handler = &proc_dointvec,
929 },
930 {
931 .ctl_name = CTL_VM_SWAPFS_MINFREE,
932 .procname = "swapfs_minfree",
933 .data = &swapfs_minfree,
934 .maxlen = sizeof(int),
935 .mode = 0644,
936 .proc_handler = &proc_dointvec,
937 },
36b313da
BB
938 {
939 .ctl_name = CTL_VM_SWAPFS_RESERVE,
940 .procname = "swapfs_reserve",
941 .data = &swapfs_reserve,
942 .maxlen = sizeof(int),
943 .mode = 0644,
944 .proc_handler = &proc_dointvec,
945 },
946 {
947 .ctl_name = CTL_VM_AVAILRMEM,
948 .procname = "availrmem",
4ab13d3b
BB
949 .mode = 0444,
950 .proc_handler = &proc_doavailrmem,
951 },
952 {
953 .ctl_name = CTL_VM_FREEMEM,
954 .procname = "freemem",
955 .data = (void *)2,
956 .maxlen = sizeof(int),
957 .mode = 0444,
958 .proc_handler = &proc_dofreemem,
959 },
960 {
961 .ctl_name = CTL_VM_PHYSMEM,
962 .procname = "physmem",
963 .data = &physmem,
36b313da
BB
964 .maxlen = sizeof(int),
965 .mode = 0444,
966 .proc_handler = &proc_dointvec,
967 },
968 {0},
969};
970
9ab1ac14 971#ifdef DEBUG_MUTEX
972static struct ctl_table spl_mutex_table[] = {
973 {
974 .ctl_name = CTL_MUTEX_STATS,
975 .procname = "stats",
976 .data = &mutex_stats,
977 .maxlen = sizeof(int) * MUTEX_STATS_SIZE,
978 .mode = 0444,
979 .proc_handler = &proc_dointvec,
980 },
981 {
982 .ctl_name = CTL_MUTEX_SPIN_MAX,
983 .procname = "spin_max",
984 .data = &mutex_spin_max,
985 .maxlen = sizeof(int),
986 .mode = 0644,
987 .proc_handler = &proc_dointvec,
988 },
989 {0},
990};
991#endif /* DEBUG_MUTEX */
992
57d1b188 993#ifdef DEBUG_KMEM
9ab1ac14 994static struct ctl_table spl_kmem_table[] = {
57d1b188 995 {
996 .ctl_name = CTL_KMEM_KMEMUSED,
997 .procname = "kmem_used",
998 .data = &kmem_alloc_used,
999 .maxlen = sizeof(atomic64_t),
1000 .mode = 0444,
1001 .proc_handler = &proc_doatomic64,
1002 },
1003 {
1004 .ctl_name = CTL_KMEM_KMEMMAX,
1005 .procname = "kmem_max",
1006 .data = &kmem_alloc_max,
1007 .maxlen = sizeof(unsigned long),
1008 .extra1 = &table_min,
1009 .extra2 = &table_max,
1010 .mode = 0444,
1011 .proc_handler = &proc_doulongvec_minmax,
1012 },
1013 {
1014 .ctl_name = CTL_KMEM_VMEMUSED,
1015 .procname = "vmem_used",
1016 .data = &vmem_alloc_used,
1017 .maxlen = sizeof(atomic64_t),
1018 .mode = 0444,
1019 .proc_handler = &proc_doatomic64,
1020 },
1021 {
1022 .ctl_name = CTL_KMEM_VMEMMAX,
1023 .procname = "vmem_max",
1024 .data = &vmem_alloc_max,
1025 .maxlen = sizeof(unsigned long),
1026 .extra1 = &table_min,
1027 .extra2 = &table_max,
1028 .mode = 0444,
1029 .proc_handler = &proc_doulongvec_minmax,
1030 },
9ab1ac14 1031 {0},
1032};
04a479f7 1033#endif /* DEBUG_KMEM */
1034
1035#ifdef DEBUG_KSTAT
1036static struct ctl_table spl_kstat_table[] = {
1037 {0},
1038};
1039#endif /* DEBUG_KSTAT */
9ab1ac14 1040
1041static struct ctl_table spl_table[] = {
1042 /* NB No .strategy entries have been provided since
1043 * sysctl(8) prefers to go via /proc for portability.
1044 */
1045 {
1046 .ctl_name = CTL_VERSION,
1047 .procname = "version",
1048 .data = spl_version,
1049 .maxlen = sizeof(spl_version),
1050 .mode = 0444,
1051 .proc_handler = &proc_dostring,
1052 },
57d1b188 1053 {
1054 .ctl_name = CTL_HOSTID,
1055 .procname = "hostid",
1056 .data = &spl_hostid,
1057 .maxlen = sizeof(unsigned long),
1058 .mode = 0644,
1059 .proc_handler = &proc_dohostid,
1060 },
1061 {
1062 .ctl_name = CTL_HW_SERIAL,
1063 .procname = "hw_serial",
937879f1 1064 .data = hw_serial,
1065 .maxlen = sizeof(hw_serial),
57d1b188 1066 .mode = 0444,
1067 .proc_handler = &proc_dostring,
1068 },
d1ff2312
BB
1069#ifndef HAVE_KALLSYMS_LOOKUP_NAME
1070 {
1071 .ctl_name = CTL_KALLSYMS,
1072 .procname = "kallsyms_lookup_name",
1073 .data = &spl_kallsyms_lookup_name_fn,
1074 .maxlen = sizeof(unsigned long),
1075 .mode = 0644,
1076 .proc_handler = &proc_dokallsyms_lookup_name,
1077 },
1078#endif
9ab1ac14 1079 {
1080 .ctl_name = CTL_SPL_DEBUG,
1081 .procname = "debug",
1082 .mode = 0555,
1083 .child = spl_debug_table,
1084 },
36b313da
BB
1085 {
1086 .ctl_name = CTL_SPL_VM,
1087 .procname = "vm",
1088 .mode = 0555,
1089 .child = spl_vm_table,
1090 },
9ab1ac14 1091#ifdef DEBUG_MUTEX
1092 {
1093 .ctl_name = CTL_SPL_MUTEX,
1094 .procname = "mutex",
1095 .mode = 0555,
1096 .child = spl_mutex_table,
1097 },
1098#endif
1099#ifdef DEBUG_KMEM
1100 {
1101 .ctl_name = CTL_SPL_KMEM,
1102 .procname = "kmem",
1103 .mode = 0555,
1104 .child = spl_kmem_table,
1105 },
04a479f7 1106#endif
1107#ifdef DEBUG_KSTAT
1108 {
1109 .ctl_name = CTL_SPL_KSTAT,
1110 .procname = "kstat",
1111 .mode = 0555,
1112 .child = spl_kstat_table,
1113 },
9ab1ac14 1114#endif
57d1b188 1115 { 0 },
1116};
1117
9ab1ac14 1118static struct ctl_table spl_dir[] = {
57d1b188 1119 {
1120 .ctl_name = CTL_SPL,
1121 .procname = "spl",
1122 .mode = 0555,
1123 .child = spl_table,
1124 },
57d86234 1125 { 0 }
1126};
1127
1128static struct ctl_table spl_root[] = {
1129 {
1130 .ctl_name = CTL_KERN,
1131 .procname = "kernel",
1132 .mode = 0555,
1133 .child = spl_dir,
1134 },
1135 { 0 }
57d1b188 1136};
1137
404992e3 1138static int
1139proc_dir_entry_match(int len, const char *name, struct proc_dir_entry *de)
1140{
1141 if (de->namelen != len)
1142 return 0;
1143
1144 return !memcmp(name, de->name, len);
1145}
1146
04a479f7 1147struct proc_dir_entry *
404992e3 1148proc_dir_entry_find(struct proc_dir_entry *root, const char *str)
1149{
1150 struct proc_dir_entry *de;
1151
1152 for (de = root->subdir; de; de = de->next)
1153 if (proc_dir_entry_match(strlen(str), str, de))
1154 return de;
1155
1156 return NULL;
1157}
1158
04a479f7 1159int
1160proc_dir_entries(struct proc_dir_entry *root)
1161{
1162 struct proc_dir_entry *de;
1163 int i = 0;
1164
1165 for (de = root->subdir; de; de = de->next)
1166 i++;
1167
1168 return i;
1169}
1170
57d1b188 1171int
1172proc_init(void)
1173{
404992e3 1174 int rc = 0;
57d1b188 1175 ENTRY;
1176
1177#ifdef CONFIG_SYSCTL
57d86234 1178 spl_header = spl_register_sysctl_table(spl_root, 0);
57d1b188 1179 if (spl_header == NULL)
1180 RETURN(-EUNATCH);
c30df9c8 1181#endif /* CONFIG_SYSCTL */
9ab1ac14 1182
57d86234 1183#if defined(DEBUG_MUTEX) || defined(DEBUG_KMEM) || defined(DEBUG_KSTAT)
c30df9c8 1184 proc_spl = proc_mkdir("spl", NULL);
1185 if (proc_spl == NULL)
404992e3 1186 GOTO(out, rc = -EUNATCH);
1187
9ab1ac14 1188#ifdef DEBUG_MUTEX
c30df9c8 1189 proc_spl_mutex = proc_mkdir("mutex", proc_spl);
1190 if (proc_spl_mutex == NULL)
404992e3 1191 GOTO(out, rc = -EUNATCH);
1192
c30df9c8 1193 proc_spl_mutex_stats = create_proc_entry("stats_per", 0444,
1194 proc_spl_mutex);
1195 if (proc_spl_mutex_stats == NULL)
404992e3 1196 GOTO(out, rc = -EUNATCH);
1197
c30df9c8 1198 proc_spl_mutex_stats->proc_fops = &proc_mutex_operations;
9ab1ac14 1199#endif /* DEBUG_MUTEX */
04a479f7 1200
1201#ifdef DEBUG_KMEM
c30df9c8 1202 proc_spl_kmem = proc_mkdir("kmem", proc_spl);
1203 if (proc_spl_kmem == NULL)
1204 GOTO(out, rc = -EUNATCH);
ff449ac4 1205
1206 proc_spl_kmem_slab = create_proc_entry("slab", 0444, proc_spl_kmem);
1207 if (proc_spl_kmem_slab == NULL)
1208 GOTO(out, rc = -EUNATCH);
1209
1210 proc_spl_kmem_slab->proc_fops = &proc_slab_operations;
04a479f7 1211#endif /* DEBUG_KMEM */
1212
1213#ifdef DEBUG_KSTAT
c30df9c8 1214 proc_spl_kstat = proc_mkdir("kstat", proc_spl);
1215 if (proc_spl_kstat == NULL)
1216 GOTO(out, rc = -EUNATCH);
04a479f7 1217#endif /* DEBUG_KSTAT */
1218
404992e3 1219out:
c30df9c8 1220 if (rc) {
1221 remove_proc_entry("kstat", proc_spl);
ff449ac4 1222#ifdef DEBUG_KMEM
1223 remove_proc_entry("slab", proc_spl_kmem);
1224#endif
c30df9c8 1225 remove_proc_entry("kmem", proc_spl);
4afaaefa 1226#ifdef DEBUG_MUTEX
c30df9c8 1227 remove_proc_entry("stats_per", proc_spl_mutex);
4afaaefa 1228#endif
c30df9c8 1229 remove_proc_entry("mutex", proc_spl);
a02118a8 1230 remove_proc_entry("spl", NULL);
c30df9c8 1231#ifdef CONFIG_SYSCTL
1232 spl_unregister_sysctl_table(spl_header);
404992e3 1233#endif /* CONFIG_SYSCTL */
c30df9c8 1234 }
1235#endif /* DEBUG_MUTEX || DEBUG_KMEM || DEBUG_KSTAT */
1236
404992e3 1237 RETURN(rc);
57d1b188 1238}
1239
1240void
1241proc_fini(void)
1242{
1243 ENTRY;
1244
c30df9c8 1245#if defined(DEBUG_MUTEX) || defined(DEBUG_KMEM) || defined(DEBUG_KSTAT)
1246 remove_proc_entry("kstat", proc_spl);
ff449ac4 1247#ifdef DEBUG_KMEM
1248 remove_proc_entry("slab", proc_spl_kmem);
1249#endif
c30df9c8 1250 remove_proc_entry("kmem", proc_spl);
4afaaefa 1251#ifdef DEBUG_MUTEX
c30df9c8 1252 remove_proc_entry("stats_per", proc_spl_mutex);
4afaaefa 1253#endif
c30df9c8 1254 remove_proc_entry("mutex", proc_spl);
a02118a8 1255 remove_proc_entry("spl", NULL);
c30df9c8 1256#endif /* DEBUG_MUTEX || DEBUG_KMEM || DEBUG_KSTAT */
1257
57d1b188 1258#ifdef CONFIG_SYSCTL
1259 ASSERT(spl_header != NULL);
57d86234 1260 spl_unregister_sysctl_table(spl_header);
c30df9c8 1261#endif /* CONFIG_SYSCTL */
1262
57d1b188 1263 EXIT;
1264}