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