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