]> git.proxmox.com Git - mirror_spl.git/blame - module/spl/spl-proc.c
Lower minimum objects/slab threshold
[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 8 * This file is part of the SPL, Solaris Porting Layer.
3d6af2dd 9 * For details, see <http://zfsonlinux.org/>.
716154c5
BB
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>
e3c4d448 32#include <linux/version.h>
55abb092 33#include <spl-debug.h>
57d1b188 34
b17edc10
BB
35#ifdef SS_DEBUG_SUBSYS
36#undef SS_DEBUG_SUBSYS
57d1b188 37#endif
38
b17edc10 39#define SS_DEBUG_SUBSYS SS_PROC
57d1b188 40
e3c4d448
RY
41#if defined(CONSTIFY_PLUGIN) && LINUX_VERSION_CODE >= KERNEL_VERSION(3,8,0)
42typedef struct ctl_table __no_const spl_ctl_table;
43#else
44typedef struct ctl_table spl_ctl_table;
45#endif
46
404992e3 47#ifdef DEBUG_KMEM
57d1b188 48static unsigned long table_min = 0;
49static unsigned long table_max = ~0;
404992e3 50#endif
51
404992e3 52static struct ctl_table_header *spl_header = NULL;
c30df9c8 53static struct proc_dir_entry *proc_spl = NULL;
04a479f7 54#ifdef DEBUG_KMEM
c30df9c8 55static struct proc_dir_entry *proc_spl_kmem = NULL;
ff449ac4 56static struct proc_dir_entry *proc_spl_kmem_slab = NULL;
c30df9c8 57#endif /* DEBUG_KMEM */
c30df9c8 58struct proc_dir_entry *proc_spl_kstat = NULL;
57d1b188 59
57d1b188 60static int
61proc_copyin_string(char *kbuffer, int kbuffer_size,
62 const char *ubuffer, int ubuffer_size)
63{
64 int size;
65
66 if (ubuffer_size > kbuffer_size)
67 return -EOVERFLOW;
68
69 if (copy_from_user((void *)kbuffer, (void *)ubuffer, ubuffer_size))
70 return -EFAULT;
71
72 /* strip trailing whitespace */
73 size = strnlen(kbuffer, ubuffer_size);
74 while (size-- >= 0)
75 if (!isspace(kbuffer[size]))
76 break;
77
78 /* empty string */
79 if (size < 0)
80 return -EINVAL;
81
82 /* no space to terminate */
83 if (size == kbuffer_size)
84 return -EOVERFLOW;
85
86 kbuffer[size + 1] = 0;
87 return 0;
88}
89
90static int
91proc_copyout_string(char *ubuffer, int ubuffer_size,
92 const char *kbuffer, char *append)
93{
94 /* NB if 'append' != NULL, it's a single character to append to the
95 * copied out string - usually "\n", for /proc entries and
96 * (i.e. a terminating zero byte) for sysctl entries
97 */
98 int size = MIN(strlen(kbuffer), ubuffer_size);
99
100 if (copy_to_user(ubuffer, kbuffer, size))
101 return -EFAULT;
102
103 if (append != NULL && size < ubuffer_size) {
104 if (copy_to_user(ubuffer + size, append, 1))
105 return -EFAULT;
106
107 size++;
108 }
109
110 return size;
111}
112
4b2220f0 113#ifdef DEBUG_LOG
0fac9c9e
BB
114static int
115proc_dobitmasks(struct ctl_table *table, int write,
116 void __user *buffer, size_t *lenp, loff_t *ppos)
57d1b188 117{
118 unsigned long *mask = table->data;
119 int is_subsys = (mask == &spl_debug_subsys) ? 1 : 0;
120 int is_printk = (mask == &spl_debug_printk) ? 1 : 0;
121 int size = 512, rc;
122 char *str;
b17edc10 123 SENTRY;
57d1b188 124
125 str = kmem_alloc(size, KM_SLEEP);
126 if (str == NULL)
b17edc10 127 SRETURN(-ENOMEM);
57d1b188 128
129 if (write) {
130 rc = proc_copyin_string(str, size, buffer, *lenp);
131 if (rc < 0)
b17edc10 132 SRETURN(rc);
57d1b188 133
134 rc = spl_debug_str2mask(mask, str, is_subsys);
135 /* Always print BUG/ASSERT to console, so keep this mask */
136 if (is_printk)
b17edc10 137 *mask |= SD_EMERG;
57d1b188 138
139 *ppos += *lenp;
140 } else {
141 rc = spl_debug_mask2str(str, size, *mask, is_subsys);
142 if (*ppos >= rc)
143 rc = 0;
144 else
145 rc = proc_copyout_string(buffer, *lenp,
146 str + *ppos, "\n");
147 if (rc >= 0) {
148 *lenp = rc;
149 *ppos += rc;
150 }
151 }
152
153 kmem_free(str, size);
b17edc10 154 SRETURN(rc);
57d1b188 155}
156
0fac9c9e
BB
157static int
158proc_debug_mb(struct ctl_table *table, int write,
159 void __user *buffer, size_t *lenp, loff_t *ppos)
57d1b188 160{
161 char str[32];
162 int rc, len;
b17edc10 163 SENTRY;
57d1b188 164
165 if (write) {
166 rc = proc_copyin_string(str, sizeof(str), buffer, *lenp);
167 if (rc < 0)
b17edc10 168 SRETURN(rc);
57d1b188 169
170 rc = spl_debug_set_mb(simple_strtoul(str, NULL, 0));
171 *ppos += *lenp;
172 } else {
173 len = snprintf(str, sizeof(str), "%d", spl_debug_get_mb());
174 if (*ppos >= len)
175 rc = 0;
176 else
3977f837 177 rc = proc_copyout_string(buffer,*lenp,str+*ppos,"\n");
57d1b188 178
179 if (rc >= 0) {
180 *lenp = rc;
181 *ppos += rc;
182 }
183 }
184
b17edc10 185 SRETURN(rc);
57d1b188 186}
187
0fac9c9e
BB
188static int
189proc_dump_kernel(struct ctl_table *table, int write,
190 void __user *buffer, size_t *lenp, loff_t *ppos)
57d1b188 191{
b17edc10 192 SENTRY;
57d1b188 193
194 if (write) {
7fea96c0 195 spl_debug_dumplog(0);
57d1b188 196 *ppos += *lenp;
197 } else {
198 *lenp = 0;
199 }
200
b17edc10 201 SRETURN(0);
57d1b188 202}
203
0fac9c9e
BB
204static int
205proc_force_bug(struct ctl_table *table, int write,
206 void __user *buffer, size_t *lenp, loff_t *ppos)
57d1b188 207{
b17edc10 208 SENTRY;
57d1b188 209
55abb092
BB
210 if (write)
211 PANIC("Crashing due to forced panic\n");
212 else
57d1b188 213 *lenp = 0;
57d1b188 214
b17edc10 215 SRETURN(0);
57d1b188 216}
217
0fac9c9e
BB
218static int
219proc_console_max_delay_cs(struct ctl_table *table, int write,
220 void __user *buffer, size_t *lenp, loff_t *ppos)
57d1b188 221{
222 int rc, max_delay_cs;
e3c4d448 223 spl_ctl_table dummy = *table;
57d1b188 224 long d;
b17edc10 225 SENTRY;
57d1b188 226
227 dummy.data = &max_delay_cs;
228 dummy.proc_handler = &proc_dointvec;
229
230 if (write) {
231 max_delay_cs = 0;
0fac9c9e 232 rc = proc_dointvec(&dummy, write, buffer, lenp, ppos);
57d1b188 233 if (rc < 0)
b17edc10 234 SRETURN(rc);
57d1b188 235
236 if (max_delay_cs <= 0)
b17edc10 237 SRETURN(-EINVAL);
57d1b188 238
239 d = (max_delay_cs * HZ) / 100;
240 if (d == 0 || d < spl_console_min_delay)
b17edc10 241 SRETURN(-EINVAL);
57d1b188 242
243 spl_console_max_delay = d;
244 } else {
245 max_delay_cs = (spl_console_max_delay * 100) / HZ;
0fac9c9e 246 rc = proc_dointvec(&dummy, write, buffer, lenp, ppos);
57d1b188 247 }
248
b17edc10 249 SRETURN(rc);
57d1b188 250}
251
0fac9c9e
BB
252static int
253proc_console_min_delay_cs(struct ctl_table *table, int write,
254 void __user *buffer, size_t *lenp, loff_t *ppos)
57d1b188 255{
256 int rc, min_delay_cs;
e3c4d448 257 spl_ctl_table dummy = *table;
57d1b188 258 long d;
b17edc10 259 SENTRY;
57d1b188 260
261 dummy.data = &min_delay_cs;
262 dummy.proc_handler = &proc_dointvec;
263
264 if (write) {
265 min_delay_cs = 0;
0fac9c9e 266 rc = proc_dointvec(&dummy, write, buffer, lenp, ppos);
57d1b188 267 if (rc < 0)
b17edc10 268 SRETURN(rc);
57d1b188 269
270 if (min_delay_cs <= 0)
b17edc10 271 SRETURN(-EINVAL);
57d1b188 272
273 d = (min_delay_cs * HZ) / 100;
274 if (d == 0 || d > spl_console_max_delay)
b17edc10 275 SRETURN(-EINVAL);
57d1b188 276
277 spl_console_min_delay = d;
278 } else {
279 min_delay_cs = (spl_console_min_delay * 100) / HZ;
0fac9c9e 280 rc = proc_dointvec(&dummy, write, buffer, lenp, ppos);
57d1b188 281 }
282
b17edc10 283 SRETURN(rc);
57d1b188 284}
285
0fac9c9e
BB
286static int
287proc_console_backoff(struct ctl_table *table, int write,
288 void __user *buffer, size_t *lenp, loff_t *ppos)
57d1b188 289{
290 int rc, backoff;
e3c4d448 291 spl_ctl_table dummy = *table;
b17edc10 292 SENTRY;
57d1b188 293
294 dummy.data = &backoff;
295 dummy.proc_handler = &proc_dointvec;
296
297 if (write) {
298 backoff = 0;
0fac9c9e 299 rc = proc_dointvec(&dummy, write, buffer, lenp, ppos);
57d1b188 300 if (rc < 0)
b17edc10 301 SRETURN(rc);
57d1b188 302
303 if (backoff <= 0)
b17edc10 304 SRETURN(-EINVAL);
57d1b188 305
306 spl_console_backoff = backoff;
307 } else {
308 backoff = spl_console_backoff;
0fac9c9e 309 rc = proc_dointvec(&dummy, write, buffer, lenp, ppos);
57d1b188 310 }
311
b17edc10 312 SRETURN(rc);
57d1b188 313}
4b2220f0 314#endif /* DEBUG_LOG */
57d1b188 315
c6dc93d6 316#ifdef DEBUG_KMEM
0fac9c9e
BB
317static int
318proc_domemused(struct ctl_table *table, int write,
319 void __user *buffer, size_t *lenp, loff_t *ppos)
57d1b188 320{
321 int rc = 0;
322 unsigned long min = 0, max = ~0, val;
e3c4d448 323 spl_ctl_table dummy = *table;
b17edc10 324 SENTRY;
57d1b188 325
326 dummy.data = &val;
327 dummy.proc_handler = &proc_dointvec;
328 dummy.extra1 = &min;
329 dummy.extra2 = &max;
330
331 if (write) {
332 *ppos += *lenp;
333 } else {
d04c8a56 334# ifdef HAVE_ATOMIC64_T
550f1705 335 val = atomic64_read((atomic64_t *)table->data);
d04c8a56
BB
336# else
337 val = atomic_read((atomic_t *)table->data);
338# endif /* HAVE_ATOMIC64_T */
0fac9c9e 339 rc = proc_doulongvec_minmax(&dummy, write, buffer, lenp, ppos);
57d1b188 340 }
341
b17edc10 342 SRETURN(rc);
57d1b188 343}
3336e29c 344
0fac9c9e
BB
345static int
346proc_doslab(struct ctl_table *table, int write,
347 void __user *buffer, size_t *lenp, loff_t *ppos)
3336e29c
BB
348{
349 int rc = 0;
350 unsigned long min = 0, max = ~0, val = 0, mask;
e3c4d448 351 spl_ctl_table dummy = *table;
3336e29c
BB
352 spl_kmem_cache_t *skc;
353 SENTRY;
354
355 dummy.data = &val;
356 dummy.proc_handler = &proc_dointvec;
357 dummy.extra1 = &min;
358 dummy.extra2 = &max;
359
360 if (write) {
361 *ppos += *lenp;
362 } else {
363 down_read(&spl_kmem_cache_sem);
364 mask = (unsigned long)table->data;
365
366 list_for_each_entry(skc, &spl_kmem_cache_list, skc_list) {
367
368 /* Only use slabs of the correct kmem/vmem type */
369 if (!(skc->skc_flags & mask))
370 continue;
371
372 /* Sum the specified field for selected slabs */
373 switch (mask & (KMC_TOTAL | KMC_ALLOC | KMC_MAX)) {
374 case KMC_TOTAL:
375 val += skc->skc_slab_size * skc->skc_slab_total;
376 break;
377 case KMC_ALLOC:
378 val += skc->skc_obj_size * skc->skc_obj_alloc;
379 break;
380 case KMC_MAX:
381 val += skc->skc_obj_size * skc->skc_obj_max;
382 break;
383 }
384 }
385
386 up_read(&spl_kmem_cache_sem);
0fac9c9e 387 rc = proc_doulongvec_minmax(&dummy, write, buffer, lenp, ppos);
3336e29c
BB
388 }
389
390 SRETURN(rc);
391}
c6dc93d6 392#endif /* DEBUG_KMEM */
57d1b188 393
0fac9c9e
BB
394static int
395proc_dohostid(struct ctl_table *table, int write,
396 void __user *buffer, size_t *lenp, loff_t *ppos)
57d1b188 397{
398 int len, rc = 0;
57d1b188 399 char *end, str[32];
b17edc10 400 SENTRY;
57d1b188 401
402 if (write) {
0fac9c9e 403 /* We can't use proc_doulongvec_minmax() in the write
c95b308d 404 * case here because hostid while a hex value has no
a0b5ae8a 405 * leading 0x which confuses the helper function. */
57d1b188 406 rc = proc_copyin_string(str, sizeof(str), buffer, *lenp);
407 if (rc < 0)
b17edc10 408 SRETURN(rc);
57d1b188 409
fa6f7d8f 410 spl_hostid = simple_strtoul(str, &end, 16);
a0b5ae8a 411 if (str == end)
b17edc10 412 SRETURN(-EINVAL);
57d1b188 413
57d1b188 414 } else {
c95b308d 415 len = snprintf(str, sizeof(str), "%lx", spl_hostid);
57d1b188 416 if (*ppos >= len)
417 rc = 0;
418 else
3977f837 419 rc = proc_copyout_string(buffer,*lenp,str+*ppos,"\n");
57d1b188 420
421 if (rc >= 0) {
422 *lenp = rc;
423 *ppos += rc;
424 }
425 }
426
b17edc10 427 SRETURN(rc);
57d1b188 428}
429
ff449ac4 430#ifdef DEBUG_KMEM
431static void
432slab_seq_show_headers(struct seq_file *f)
433{
d0a1038f
BB
434 seq_printf(f,
435 "--------------------- cache ----------"
436 "--------------------------------------------- "
437 "----- slab ------ "
165f13c3
BB
438 "---- object ----- "
439 "--- emergency ---\n");
d0a1038f
BB
440 seq_printf(f,
441 "name "
442 " flags size alloc slabsize objsize "
443 "total alloc max "
165f13c3
BB
444 "total alloc max "
445 "dlock alloc max\n");
ff449ac4 446}
447
448static int
449slab_seq_show(struct seq_file *f, void *p)
450{
242f539a 451 spl_kmem_cache_t *skc = p;
ff449ac4 452
242f539a 453 ASSERT(skc->skc_magic == SKC_MAGIC);
ff449ac4 454
a073aeb0
BB
455 /*
456 * Backed by Linux slab see /proc/slabinfo.
457 */
458 if (skc->skc_flags & KMC_SLAB)
459 return (0);
460
242f539a 461 spin_lock(&skc->skc_lock);
d0a1038f
BB
462 seq_printf(f, "%-36s ", skc->skc_name);
463 seq_printf(f, "0x%05lx %9lu %9lu %8u %8u "
165f13c3 464 "%5lu %5lu %5lu %5lu %5lu %5lu %5lu %5lu %5lu\n",
d0a1038f
BB
465 (long unsigned)skc->skc_flags,
466 (long unsigned)(skc->skc_slab_size * skc->skc_slab_total),
467 (long unsigned)(skc->skc_obj_size * skc->skc_obj_alloc),
468 (unsigned)skc->skc_slab_size,
469 (unsigned)skc->skc_obj_size,
470 (long unsigned)skc->skc_slab_total,
471 (long unsigned)skc->skc_slab_alloc,
472 (long unsigned)skc->skc_slab_max,
473 (long unsigned)skc->skc_obj_total,
474 (long unsigned)skc->skc_obj_alloc,
e2dcc6e2 475 (long unsigned)skc->skc_obj_max,
165f13c3 476 (long unsigned)skc->skc_obj_deadlock,
e2dcc6e2
BB
477 (long unsigned)skc->skc_obj_emergency,
478 (long unsigned)skc->skc_obj_emergency_max);
242f539a
BB
479
480 spin_unlock(&skc->skc_lock);
ff449ac4 481
482 return 0;
483}
484
485static void *
486slab_seq_start(struct seq_file *f, loff_t *pos)
487{
488 struct list_head *p;
489 loff_t n = *pos;
b17edc10 490 SENTRY;
ff449ac4 491
492 down_read(&spl_kmem_cache_sem);
493 if (!n)
494 slab_seq_show_headers(f);
495
496 p = spl_kmem_cache_list.next;
497 while (n--) {
498 p = p->next;
499 if (p == &spl_kmem_cache_list)
b17edc10 500 SRETURN(NULL);
ff449ac4 501 }
502
b17edc10 503 SRETURN(list_entry(p, spl_kmem_cache_t, skc_list));
ff449ac4 504}
505
506static void *
507slab_seq_next(struct seq_file *f, void *p, loff_t *pos)
508{
509 spl_kmem_cache_t *skc = p;
b17edc10 510 SENTRY;
ff449ac4 511
512 ++*pos;
b17edc10 513 SRETURN((skc->skc_list.next == &spl_kmem_cache_list) ?
3977f837 514 NULL : list_entry(skc->skc_list.next,spl_kmem_cache_t,skc_list));
ff449ac4 515}
516
517static void
518slab_seq_stop(struct seq_file *f, void *v)
519{
520 up_read(&spl_kmem_cache_sem);
521}
522
523static struct seq_operations slab_seq_ops = {
524 .show = slab_seq_show,
525 .start = slab_seq_start,
526 .next = slab_seq_next,
527 .stop = slab_seq_stop,
528};
529
530static int
531proc_slab_open(struct inode *inode, struct file *filp)
532{
533 return seq_open(filp, &slab_seq_ops);
534}
535
536static struct file_operations proc_slab_operations = {
537 .open = proc_slab_open,
538 .read = seq_read,
539 .llseek = seq_lseek,
540 .release = seq_release,
541};
542#endif /* DEBUG_KMEM */
543
4b2220f0 544#ifdef DEBUG_LOG
9ab1ac14 545static struct ctl_table spl_debug_table[] = {
57d1b188 546 {
9ab1ac14 547 .procname = "subsystem",
57d1b188 548 .data = &spl_debug_subsys,
549 .maxlen = sizeof(unsigned long),
550 .mode = 0644,
551 .proc_handler = &proc_dobitmasks
552 },
553 {
9ab1ac14 554 .procname = "mask",
57d1b188 555 .data = &spl_debug_mask,
556 .maxlen = sizeof(unsigned long),
557 .mode = 0644,
558 .proc_handler = &proc_dobitmasks
559 },
560 {
9ab1ac14 561 .procname = "printk",
57d1b188 562 .data = &spl_debug_printk,
563 .maxlen = sizeof(unsigned long),
564 .mode = 0644,
565 .proc_handler = &proc_dobitmasks
566 },
567 {
9ab1ac14 568 .procname = "mb",
57d1b188 569 .mode = 0644,
570 .proc_handler = &proc_debug_mb,
571 },
572 {
9ab1ac14 573 .procname = "binary",
57d1b188 574 .data = &spl_debug_binary,
575 .maxlen = sizeof(int),
576 .mode = 0644,
577 .proc_handler = &proc_dointvec,
578 },
579 {
57d1b188 580 .procname = "catastrophe",
581 .data = &spl_debug_catastrophe,
582 .maxlen = sizeof(int),
583 .mode = 0444,
584 .proc_handler = &proc_dointvec,
585 },
586 {
57d1b188 587 .procname = "panic_on_bug",
588 .data = &spl_debug_panic_on_bug,
589 .maxlen = sizeof(int),
590 .mode = 0644,
591 .proc_handler = &proc_dointvec
592 },
593 {
9ab1ac14 594 .procname = "path",
57d1b188 595 .data = spl_debug_file_path,
596 .maxlen = sizeof(spl_debug_file_path),
597 .mode = 0644,
598 .proc_handler = &proc_dostring,
599 },
600 {
9ab1ac14 601 .procname = "dump",
57d1b188 602 .mode = 0200,
603 .proc_handler = &proc_dump_kernel,
604 },
9c91800d 605 {
57d1b188 606 .procname = "force_bug",
607 .mode = 0200,
608 .proc_handler = &proc_force_bug,
609 },
610 {
57d1b188 611 .procname = "console_ratelimit",
612 .data = &spl_console_ratelimit,
613 .maxlen = sizeof(int),
614 .mode = 0644,
615 .proc_handler = &proc_dointvec,
616 },
617 {
57d1b188 618 .procname = "console_max_delay_centisecs",
619 .maxlen = sizeof(int),
620 .mode = 0644,
621 .proc_handler = &proc_console_max_delay_cs,
622 },
623 {
57d1b188 624 .procname = "console_min_delay_centisecs",
625 .maxlen = sizeof(int),
626 .mode = 0644,
627 .proc_handler = &proc_console_min_delay_cs,
628 },
629 {
57d1b188 630 .procname = "console_backoff",
631 .maxlen = sizeof(int),
632 .mode = 0644,
633 .proc_handler = &proc_console_backoff,
634 },
635 {
57d1b188 636 .procname = "stack_max",
637 .data = &spl_debug_stack,
638 .maxlen = sizeof(int),
639 .mode = 0444,
640 .proc_handler = &proc_dointvec,
641 },
9ab1ac14 642 {0},
643};
4b2220f0 644#endif /* DEBUG_LOG */
9ab1ac14 645
57d1b188 646#ifdef DEBUG_KMEM
9ab1ac14 647static struct ctl_table spl_kmem_table[] = {
57d1b188 648 {
57d1b188 649 .procname = "kmem_used",
650 .data = &kmem_alloc_used,
d04c8a56 651# ifdef HAVE_ATOMIC64_T
57d1b188 652 .maxlen = sizeof(atomic64_t),
d04c8a56
BB
653# else
654 .maxlen = sizeof(atomic_t),
655# endif /* HAVE_ATOMIC64_T */
57d1b188 656 .mode = 0444,
d04c8a56 657 .proc_handler = &proc_domemused,
57d1b188 658 },
659 {
57d1b188 660 .procname = "kmem_max",
661 .data = &kmem_alloc_max,
662 .maxlen = sizeof(unsigned long),
663 .extra1 = &table_min,
664 .extra2 = &table_max,
665 .mode = 0444,
666 .proc_handler = &proc_doulongvec_minmax,
667 },
668 {
57d1b188 669 .procname = "vmem_used",
670 .data = &vmem_alloc_used,
d04c8a56 671# ifdef HAVE_ATOMIC64_T
57d1b188 672 .maxlen = sizeof(atomic64_t),
d04c8a56
BB
673# else
674 .maxlen = sizeof(atomic_t),
675# endif /* HAVE_ATOMIC64_T */
57d1b188 676 .mode = 0444,
d04c8a56 677 .proc_handler = &proc_domemused,
57d1b188 678 },
679 {
57d1b188 680 .procname = "vmem_max",
681 .data = &vmem_alloc_max,
682 .maxlen = sizeof(unsigned long),
683 .extra1 = &table_min,
684 .extra2 = &table_max,
685 .mode = 0444,
686 .proc_handler = &proc_doulongvec_minmax,
687 },
3336e29c 688 {
3336e29c
BB
689 .procname = "slab_kmem_total",
690 .data = (void *)(KMC_KMEM | KMC_TOTAL),
691 .maxlen = sizeof(unsigned long),
692 .extra1 = &table_min,
693 .extra2 = &table_max,
694 .mode = 0444,
695 .proc_handler = &proc_doslab,
696 },
697 {
3336e29c
BB
698 .procname = "slab_kmem_alloc",
699 .data = (void *)(KMC_KMEM | KMC_ALLOC),
700 .maxlen = sizeof(unsigned long),
701 .extra1 = &table_min,
702 .extra2 = &table_max,
703 .mode = 0444,
704 .proc_handler = &proc_doslab,
705 },
706 {
3336e29c
BB
707 .procname = "slab_kmem_max",
708 .data = (void *)(KMC_KMEM | KMC_MAX),
709 .maxlen = sizeof(unsigned long),
710 .extra1 = &table_min,
711 .extra2 = &table_max,
712 .mode = 0444,
713 .proc_handler = &proc_doslab,
714 },
715 {
3336e29c
BB
716 .procname = "slab_vmem_total",
717 .data = (void *)(KMC_VMEM | KMC_TOTAL),
718 .maxlen = sizeof(unsigned long),
719 .extra1 = &table_min,
720 .extra2 = &table_max,
721 .mode = 0444,
722 .proc_handler = &proc_doslab,
723 },
724 {
3336e29c
BB
725 .procname = "slab_vmem_alloc",
726 .data = (void *)(KMC_VMEM | KMC_ALLOC),
727 .maxlen = sizeof(unsigned long),
728 .extra1 = &table_min,
729 .extra2 = &table_max,
730 .mode = 0444,
731 .proc_handler = &proc_doslab,
732 },
733 {
3336e29c
BB
734 .procname = "slab_vmem_max",
735 .data = (void *)(KMC_VMEM | KMC_MAX),
736 .maxlen = sizeof(unsigned long),
737 .extra1 = &table_min,
738 .extra2 = &table_max,
739 .mode = 0444,
740 .proc_handler = &proc_doslab,
741 },
9ab1ac14 742 {0},
743};
04a479f7 744#endif /* DEBUG_KMEM */
745
04a479f7 746static struct ctl_table spl_kstat_table[] = {
747 {0},
748};
9ab1ac14 749
750static struct ctl_table spl_table[] = {
751 /* NB No .strategy entries have been provided since
752 * sysctl(8) prefers to go via /proc for portability.
753 */
754 {
9ab1ac14 755 .procname = "version",
756 .data = spl_version,
757 .maxlen = sizeof(spl_version),
758 .mode = 0444,
759 .proc_handler = &proc_dostring,
760 },
57d1b188 761 {
57d1b188 762 .procname = "hostid",
763 .data = &spl_hostid,
764 .maxlen = sizeof(unsigned long),
765 .mode = 0644,
766 .proc_handler = &proc_dohostid,
767 },
4b2220f0 768#ifdef DEBUG_LOG
9ab1ac14 769 {
9ab1ac14 770 .procname = "debug",
771 .mode = 0555,
772 .child = spl_debug_table,
773 },
4b2220f0 774#endif
9ab1ac14 775#ifdef DEBUG_KMEM
776 {
9ab1ac14 777 .procname = "kmem",
778 .mode = 0555,
779 .child = spl_kmem_table,
780 },
04a479f7 781#endif
04a479f7 782 {
04a479f7 783 .procname = "kstat",
784 .mode = 0555,
785 .child = spl_kstat_table,
786 },
57d1b188 787 { 0 },
788};
789
9ab1ac14 790static struct ctl_table spl_dir[] = {
57d1b188 791 {
57d1b188 792 .procname = "spl",
793 .mode = 0555,
794 .child = spl_table,
795 },
57d86234 796 { 0 }
797};
798
799static struct ctl_table spl_root[] = {
800 {
9c91800d
BB
801#ifdef HAVE_CTL_NAME
802 .ctl_name = CTL_KERN,
803#endif
57d86234 804 .procname = "kernel",
805 .mode = 0555,
806 .child = spl_dir,
807 },
808 { 0 }
57d1b188 809};
810
811int
1114ae6a 812spl_proc_init(void)
57d1b188 813{
404992e3 814 int rc = 0;
b17edc10 815 SENTRY;
57d1b188 816
b38bf6a4 817 spl_header = register_sysctl_table(spl_root);
57d1b188 818 if (spl_header == NULL)
b17edc10 819 SRETURN(-EUNATCH);
9ab1ac14 820
c30df9c8 821 proc_spl = proc_mkdir("spl", NULL);
822 if (proc_spl == NULL)
b17edc10 823 SGOTO(out, rc = -EUNATCH);
404992e3 824
04a479f7 825#ifdef DEBUG_KMEM
c30df9c8 826 proc_spl_kmem = proc_mkdir("kmem", proc_spl);
827 if (proc_spl_kmem == NULL)
b17edc10 828 SGOTO(out, rc = -EUNATCH);
ff449ac4 829
f2a745c4
RY
830 proc_spl_kmem_slab = proc_create_data("slab", 0444,
831 proc_spl_kmem, &proc_slab_operations, NULL);
ff449ac4 832 if (proc_spl_kmem_slab == NULL)
b17edc10 833 SGOTO(out, rc = -EUNATCH);
ff449ac4 834
04a479f7 835#endif /* DEBUG_KMEM */
836
c30df9c8 837 proc_spl_kstat = proc_mkdir("kstat", proc_spl);
838 if (proc_spl_kstat == NULL)
b17edc10 839 SGOTO(out, rc = -EUNATCH);
404992e3 840out:
c30df9c8 841 if (rc) {
842 remove_proc_entry("kstat", proc_spl);
ff449ac4 843#ifdef DEBUG_KMEM
844 remove_proc_entry("slab", proc_spl_kmem);
c30df9c8 845 remove_proc_entry("kmem", proc_spl);
055ffd98 846#endif
a02118a8 847 remove_proc_entry("spl", NULL);
b38bf6a4 848 unregister_sysctl_table(spl_header);
c30df9c8 849 }
c30df9c8 850
b17edc10 851 SRETURN(rc);
57d1b188 852}
853
854void
1114ae6a 855spl_proc_fini(void)
57d1b188 856{
b17edc10 857 SENTRY;
57d1b188 858
c30df9c8 859 remove_proc_entry("kstat", proc_spl);
ff449ac4 860#ifdef DEBUG_KMEM
861 remove_proc_entry("slab", proc_spl_kmem);
c30df9c8 862 remove_proc_entry("kmem", proc_spl);
055ffd98 863#endif
a02118a8 864 remove_proc_entry("spl", NULL);
c30df9c8 865
57d1b188 866 ASSERT(spl_header != NULL);
b38bf6a4 867 unregister_sysctl_table(spl_header);
c30df9c8 868
b17edc10 869 SEXIT;
57d1b188 870}