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