]> git.proxmox.com Git - mirror_spl.git/blame - module/spl/spl-proc.c
Merge branch 'splat'
[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 */
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);
549 if (str == end)
b17edc10 550 SRETURN(-EINVAL);
d1ff2312
BB
551
552 *ppos += *lenp;
553 } else {
554 len = snprintf(str, sizeof(str), "%lx",
555 (unsigned long)spl_kallsyms_lookup_name_fn);
556 if (*ppos >= len)
557 rc = 0;
558 else
559 rc = proc_copyout_string(buffer,*lenp,str+*ppos,"\n");
560
561 if (rc >= 0) {
562 *lenp = rc;
563 *ppos += rc;
564 }
565 }
566
b17edc10 567 SRETURN(rc);
d1ff2312
BB
568}
569#endif /* HAVE_KALLSYMS_LOOKUP_NAME */
570
3977f837 571SPL_PROC_HANDLER(proc_doavailrmem)
4ab13d3b
BB
572{
573 int len, rc = 0;
574 char str[32];
b17edc10 575 SENTRY;
4ab13d3b
BB
576
577 if (write) {
578 *ppos += *lenp;
579 } else {
3977f837
BB
580 len = snprintf(str, sizeof(str), "%lu",
581 (unsigned long)availrmem);
4ab13d3b
BB
582 if (*ppos >= len)
583 rc = 0;
584 else
3977f837 585 rc = proc_copyout_string(buffer,*lenp,str+*ppos,"\n");
4ab13d3b
BB
586
587 if (rc >= 0) {
588 *lenp = rc;
589 *ppos += rc;
590 }
591 }
592
b17edc10 593 SRETURN(rc);
4ab13d3b
BB
594}
595
3977f837 596SPL_PROC_HANDLER(proc_dofreemem)
4ab13d3b
BB
597{
598 int len, rc = 0;
599 char str[32];
b17edc10 600 SENTRY;
4ab13d3b
BB
601
602 if (write) {
603 *ppos += *lenp;
604 } else {
605 len = snprintf(str, sizeof(str), "%lu", (unsigned long)freemem);
606 if (*ppos >= len)
607 rc = 0;
608 else
3977f837 609 rc = proc_copyout_string(buffer,*lenp,str+*ppos,"\n");
4ab13d3b
BB
610
611 if (rc >= 0) {
612 *lenp = rc;
613 *ppos += rc;
614 }
615 }
616
b17edc10 617 SRETURN(rc);
4ab13d3b
BB
618}
619
ff449ac4 620#ifdef DEBUG_KMEM
621static void
622slab_seq_show_headers(struct seq_file *f)
623{
d0a1038f
BB
624 seq_printf(f,
625 "--------------------- cache ----------"
626 "--------------------------------------------- "
627 "----- slab ------ "
e2dcc6e2 628 "---- object -----------------\n");
d0a1038f
BB
629 seq_printf(f,
630 "name "
631 " flags size alloc slabsize objsize "
632 "total alloc max "
e2dcc6e2 633 "total alloc max emerg max\n");
ff449ac4 634}
635
636static int
637slab_seq_show(struct seq_file *f, void *p)
638{
242f539a 639 spl_kmem_cache_t *skc = p;
ff449ac4 640
242f539a 641 ASSERT(skc->skc_magic == SKC_MAGIC);
ff449ac4 642
242f539a 643 spin_lock(&skc->skc_lock);
d0a1038f
BB
644 seq_printf(f, "%-36s ", skc->skc_name);
645 seq_printf(f, "0x%05lx %9lu %9lu %8u %8u "
e2dcc6e2 646 "%5lu %5lu %5lu %5lu %5lu %5lu %5lu %5lu\n",
d0a1038f
BB
647 (long unsigned)skc->skc_flags,
648 (long unsigned)(skc->skc_slab_size * skc->skc_slab_total),
649 (long unsigned)(skc->skc_obj_size * skc->skc_obj_alloc),
650 (unsigned)skc->skc_slab_size,
651 (unsigned)skc->skc_obj_size,
652 (long unsigned)skc->skc_slab_total,
653 (long unsigned)skc->skc_slab_alloc,
654 (long unsigned)skc->skc_slab_max,
655 (long unsigned)skc->skc_obj_total,
656 (long unsigned)skc->skc_obj_alloc,
e2dcc6e2
BB
657 (long unsigned)skc->skc_obj_max,
658 (long unsigned)skc->skc_obj_emergency,
659 (long unsigned)skc->skc_obj_emergency_max);
242f539a
BB
660
661 spin_unlock(&skc->skc_lock);
ff449ac4 662
663 return 0;
664}
665
666static void *
667slab_seq_start(struct seq_file *f, loff_t *pos)
668{
669 struct list_head *p;
670 loff_t n = *pos;
b17edc10 671 SENTRY;
ff449ac4 672
673 down_read(&spl_kmem_cache_sem);
674 if (!n)
675 slab_seq_show_headers(f);
676
677 p = spl_kmem_cache_list.next;
678 while (n--) {
679 p = p->next;
680 if (p == &spl_kmem_cache_list)
b17edc10 681 SRETURN(NULL);
ff449ac4 682 }
683
b17edc10 684 SRETURN(list_entry(p, spl_kmem_cache_t, skc_list));
ff449ac4 685}
686
687static void *
688slab_seq_next(struct seq_file *f, void *p, loff_t *pos)
689{
690 spl_kmem_cache_t *skc = p;
b17edc10 691 SENTRY;
ff449ac4 692
693 ++*pos;
b17edc10 694 SRETURN((skc->skc_list.next == &spl_kmem_cache_list) ?
3977f837 695 NULL : list_entry(skc->skc_list.next,spl_kmem_cache_t,skc_list));
ff449ac4 696}
697
698static void
699slab_seq_stop(struct seq_file *f, void *v)
700{
701 up_read(&spl_kmem_cache_sem);
702}
703
704static struct seq_operations slab_seq_ops = {
705 .show = slab_seq_show,
706 .start = slab_seq_start,
707 .next = slab_seq_next,
708 .stop = slab_seq_stop,
709};
710
711static int
712proc_slab_open(struct inode *inode, struct file *filp)
713{
714 return seq_open(filp, &slab_seq_ops);
715}
716
717static struct file_operations proc_slab_operations = {
718 .open = proc_slab_open,
719 .read = seq_read,
720 .llseek = seq_lseek,
721 .release = seq_release,
722};
723#endif /* DEBUG_KMEM */
724
4b2220f0 725#ifdef DEBUG_LOG
9ab1ac14 726static struct ctl_table spl_debug_table[] = {
57d1b188 727 {
79a3bf13 728 CTL_NAME (CTL_DEBUG_SUBSYS)
9ab1ac14 729 .procname = "subsystem",
57d1b188 730 .data = &spl_debug_subsys,
731 .maxlen = sizeof(unsigned long),
732 .mode = 0644,
733 .proc_handler = &proc_dobitmasks
734 },
735 {
79a3bf13 736 CTL_NAME (CTL_DEBUG_MASK)
9ab1ac14 737 .procname = "mask",
57d1b188 738 .data = &spl_debug_mask,
739 .maxlen = sizeof(unsigned long),
740 .mode = 0644,
741 .proc_handler = &proc_dobitmasks
742 },
743 {
79a3bf13 744 CTL_NAME (CTL_DEBUG_PRINTK)
9ab1ac14 745 .procname = "printk",
57d1b188 746 .data = &spl_debug_printk,
747 .maxlen = sizeof(unsigned long),
748 .mode = 0644,
749 .proc_handler = &proc_dobitmasks
750 },
751 {
79a3bf13 752 CTL_NAME (CTL_DEBUG_MB)
9ab1ac14 753 .procname = "mb",
57d1b188 754 .mode = 0644,
755 .proc_handler = &proc_debug_mb,
756 },
757 {
79a3bf13 758 CTL_NAME (CTL_DEBUG_BINARY)
9ab1ac14 759 .procname = "binary",
57d1b188 760 .data = &spl_debug_binary,
761 .maxlen = sizeof(int),
762 .mode = 0644,
763 .proc_handler = &proc_dointvec,
764 },
765 {
79a3bf13 766 CTL_NAME (CTL_DEBUG_CATASTROPHE)
57d1b188 767 .procname = "catastrophe",
768 .data = &spl_debug_catastrophe,
769 .maxlen = sizeof(int),
770 .mode = 0444,
771 .proc_handler = &proc_dointvec,
772 },
773 {
79a3bf13 774 CTL_NAME (CTL_DEBUG_PANIC_ON_BUG)
57d1b188 775 .procname = "panic_on_bug",
776 .data = &spl_debug_panic_on_bug,
777 .maxlen = sizeof(int),
778 .mode = 0644,
779 .proc_handler = &proc_dointvec
780 },
781 {
79a3bf13 782 CTL_NAME (CTL_DEBUG_PATH)
9ab1ac14 783 .procname = "path",
57d1b188 784 .data = spl_debug_file_path,
785 .maxlen = sizeof(spl_debug_file_path),
786 .mode = 0644,
787 .proc_handler = &proc_dostring,
788 },
789 {
79a3bf13 790 CTL_NAME (CTL_DEBUG_DUMP)
9ab1ac14 791 .procname = "dump",
57d1b188 792 .mode = 0200,
793 .proc_handler = &proc_dump_kernel,
794 },
79a3bf13 795 { CTL_NAME (CTL_DEBUG_FORCE_BUG)
57d1b188 796 .procname = "force_bug",
797 .mode = 0200,
798 .proc_handler = &proc_force_bug,
799 },
800 {
79a3bf13 801 CTL_NAME (CTL_CONSOLE_RATELIMIT)
57d1b188 802 .procname = "console_ratelimit",
803 .data = &spl_console_ratelimit,
804 .maxlen = sizeof(int),
805 .mode = 0644,
806 .proc_handler = &proc_dointvec,
807 },
808 {
79a3bf13 809 CTL_NAME (CTL_CONSOLE_MAX_DELAY_CS)
57d1b188 810 .procname = "console_max_delay_centisecs",
811 .maxlen = sizeof(int),
812 .mode = 0644,
813 .proc_handler = &proc_console_max_delay_cs,
814 },
815 {
79a3bf13 816 CTL_NAME (CTL_CONSOLE_MIN_DELAY_CS)
57d1b188 817 .procname = "console_min_delay_centisecs",
818 .maxlen = sizeof(int),
819 .mode = 0644,
820 .proc_handler = &proc_console_min_delay_cs,
821 },
822 {
79a3bf13 823 CTL_NAME (CTL_CONSOLE_BACKOFF)
57d1b188 824 .procname = "console_backoff",
825 .maxlen = sizeof(int),
826 .mode = 0644,
827 .proc_handler = &proc_console_backoff,
828 },
829 {
79a3bf13 830 CTL_NAME (CTL_DEBUG_STACK_SIZE)
57d1b188 831 .procname = "stack_max",
832 .data = &spl_debug_stack,
833 .maxlen = sizeof(int),
834 .mode = 0444,
835 .proc_handler = &proc_dointvec,
836 },
9ab1ac14 837 {0},
838};
4b2220f0 839#endif /* DEBUG_LOG */
9ab1ac14 840
36b313da
BB
841static struct ctl_table spl_vm_table[] = {
842 {
79a3bf13 843 CTL_NAME (CTL_VM_MINFREE)
36b313da
BB
844 .procname = "minfree",
845 .data = &minfree,
846 .maxlen = sizeof(int),
847 .mode = 0644,
848 .proc_handler = &proc_dointvec,
849 },
850 {
79a3bf13 851 CTL_NAME (CTL_VM_DESFREE)
36b313da
BB
852 .procname = "desfree",
853 .data = &desfree,
854 .maxlen = sizeof(int),
855 .mode = 0644,
856 .proc_handler = &proc_dointvec,
857 },
858 {
79a3bf13 859 CTL_NAME (CTL_VM_LOTSFREE)
36b313da
BB
860 .procname = "lotsfree",
861 .data = &lotsfree,
862 .maxlen = sizeof(int),
863 .mode = 0644,
864 .proc_handler = &proc_dointvec,
865 },
866 {
79a3bf13 867 CTL_NAME (CTL_VM_NEEDFREE)
36b313da
BB
868 .procname = "needfree",
869 .data = &needfree,
870 .maxlen = sizeof(int),
871 .mode = 0444,
872 .proc_handler = &proc_dointvec,
873 },
874 {
79a3bf13 875 CTL_NAME (CTL_VM_SWAPFS_MINFREE)
36b313da
BB
876 .procname = "swapfs_minfree",
877 .data = &swapfs_minfree,
878 .maxlen = sizeof(int),
879 .mode = 0644,
880 .proc_handler = &proc_dointvec,
881 },
36b313da 882 {
79a3bf13 883 CTL_NAME (CTL_VM_SWAPFS_RESERVE)
36b313da
BB
884 .procname = "swapfs_reserve",
885 .data = &swapfs_reserve,
886 .maxlen = sizeof(int),
887 .mode = 0644,
888 .proc_handler = &proc_dointvec,
889 },
890 {
79a3bf13 891 CTL_NAME (CTL_VM_AVAILRMEM)
36b313da 892 .procname = "availrmem",
4ab13d3b
BB
893 .mode = 0444,
894 .proc_handler = &proc_doavailrmem,
895 },
896 {
79a3bf13 897 CTL_NAME (CTL_VM_FREEMEM)
4ab13d3b
BB
898 .procname = "freemem",
899 .data = (void *)2,
900 .maxlen = sizeof(int),
901 .mode = 0444,
902 .proc_handler = &proc_dofreemem,
903 },
904 {
79a3bf13 905 CTL_NAME (CTL_VM_PHYSMEM)
4ab13d3b
BB
906 .procname = "physmem",
907 .data = &physmem,
36b313da
BB
908 .maxlen = sizeof(int),
909 .mode = 0444,
910 .proc_handler = &proc_dointvec,
911 },
912 {0},
913};
914
57d1b188 915#ifdef DEBUG_KMEM
9ab1ac14 916static struct ctl_table spl_kmem_table[] = {
57d1b188 917 {
79a3bf13 918 CTL_NAME (CTL_KMEM_KMEMUSED)
57d1b188 919 .procname = "kmem_used",
920 .data = &kmem_alloc_used,
d04c8a56 921# ifdef HAVE_ATOMIC64_T
57d1b188 922 .maxlen = sizeof(atomic64_t),
d04c8a56
BB
923# else
924 .maxlen = sizeof(atomic_t),
925# endif /* HAVE_ATOMIC64_T */
57d1b188 926 .mode = 0444,
d04c8a56 927 .proc_handler = &proc_domemused,
57d1b188 928 },
929 {
79a3bf13 930 CTL_NAME (CTL_KMEM_KMEMMAX)
57d1b188 931 .procname = "kmem_max",
932 .data = &kmem_alloc_max,
933 .maxlen = sizeof(unsigned long),
934 .extra1 = &table_min,
935 .extra2 = &table_max,
936 .mode = 0444,
937 .proc_handler = &proc_doulongvec_minmax,
938 },
939 {
79a3bf13 940 CTL_NAME (CTL_KMEM_VMEMUSED)
57d1b188 941 .procname = "vmem_used",
942 .data = &vmem_alloc_used,
d04c8a56 943# ifdef HAVE_ATOMIC64_T
57d1b188 944 .maxlen = sizeof(atomic64_t),
d04c8a56
BB
945# else
946 .maxlen = sizeof(atomic_t),
947# endif /* HAVE_ATOMIC64_T */
57d1b188 948 .mode = 0444,
d04c8a56 949 .proc_handler = &proc_domemused,
57d1b188 950 },
951 {
79a3bf13 952 CTL_NAME (CTL_KMEM_VMEMMAX)
57d1b188 953 .procname = "vmem_max",
954 .data = &vmem_alloc_max,
955 .maxlen = sizeof(unsigned long),
956 .extra1 = &table_min,
957 .extra2 = &table_max,
958 .mode = 0444,
959 .proc_handler = &proc_doulongvec_minmax,
960 },
3336e29c
BB
961 {
962 CTL_NAME (CTL_KMEM_SLAB_KMEMTOTAL)
963 .procname = "slab_kmem_total",
964 .data = (void *)(KMC_KMEM | KMC_TOTAL),
965 .maxlen = sizeof(unsigned long),
966 .extra1 = &table_min,
967 .extra2 = &table_max,
968 .mode = 0444,
969 .proc_handler = &proc_doslab,
970 },
971 {
972 CTL_NAME (CTL_KMEM_SLAB_KMEMALLOC)
973 .procname = "slab_kmem_alloc",
974 .data = (void *)(KMC_KMEM | KMC_ALLOC),
975 .maxlen = sizeof(unsigned long),
976 .extra1 = &table_min,
977 .extra2 = &table_max,
978 .mode = 0444,
979 .proc_handler = &proc_doslab,
980 },
981 {
982 CTL_NAME (CTL_KMEM_SLAB_KMEMMAX)
983 .procname = "slab_kmem_max",
984 .data = (void *)(KMC_KMEM | KMC_MAX),
985 .maxlen = sizeof(unsigned long),
986 .extra1 = &table_min,
987 .extra2 = &table_max,
988 .mode = 0444,
989 .proc_handler = &proc_doslab,
990 },
991 {
992 CTL_NAME (CTL_KMEM_SLAB_VMEMTOTAL)
993 .procname = "slab_vmem_total",
994 .data = (void *)(KMC_VMEM | KMC_TOTAL),
995 .maxlen = sizeof(unsigned long),
996 .extra1 = &table_min,
997 .extra2 = &table_max,
998 .mode = 0444,
999 .proc_handler = &proc_doslab,
1000 },
1001 {
1002 CTL_NAME (CTL_KMEM_SLAB_VMEMALLOC)
1003 .procname = "slab_vmem_alloc",
1004 .data = (void *)(KMC_VMEM | KMC_ALLOC),
1005 .maxlen = sizeof(unsigned long),
1006 .extra1 = &table_min,
1007 .extra2 = &table_max,
1008 .mode = 0444,
1009 .proc_handler = &proc_doslab,
1010 },
1011 {
1012 CTL_NAME (CTL_KMEM_SLAB_VMEMMAX)
1013 .procname = "slab_vmem_max",
1014 .data = (void *)(KMC_VMEM | KMC_MAX),
1015 .maxlen = sizeof(unsigned long),
1016 .extra1 = &table_min,
1017 .extra2 = &table_max,
1018 .mode = 0444,
1019 .proc_handler = &proc_doslab,
1020 },
9ab1ac14 1021 {0},
1022};
04a479f7 1023#endif /* DEBUG_KMEM */
1024
04a479f7 1025static struct ctl_table spl_kstat_table[] = {
1026 {0},
1027};
9ab1ac14 1028
1029static struct ctl_table spl_table[] = {
1030 /* NB No .strategy entries have been provided since
1031 * sysctl(8) prefers to go via /proc for portability.
1032 */
1033 {
79a3bf13 1034 CTL_NAME (CTL_VERSION)
9ab1ac14 1035 .procname = "version",
1036 .data = spl_version,
1037 .maxlen = sizeof(spl_version),
1038 .mode = 0444,
1039 .proc_handler = &proc_dostring,
1040 },
57d1b188 1041 {
79a3bf13 1042 CTL_NAME (CTL_HOSTID)
57d1b188 1043 .procname = "hostid",
1044 .data = &spl_hostid,
1045 .maxlen = sizeof(unsigned long),
1046 .mode = 0644,
1047 .proc_handler = &proc_dohostid,
1048 },
1049 {
79a3bf13 1050 CTL_NAME (CTL_HW_SERIAL)
57d1b188 1051 .procname = "hw_serial",
937879f1 1052 .data = hw_serial,
1053 .maxlen = sizeof(hw_serial),
57d1b188 1054 .mode = 0444,
1055 .proc_handler = &proc_dostring,
1056 },
d1ff2312
BB
1057#ifndef HAVE_KALLSYMS_LOOKUP_NAME
1058 {
79a3bf13 1059 CTL_NAME (CTL_KALLSYMS)
d1ff2312
BB
1060 .procname = "kallsyms_lookup_name",
1061 .data = &spl_kallsyms_lookup_name_fn,
1062 .maxlen = sizeof(unsigned long),
1063 .mode = 0644,
1064 .proc_handler = &proc_dokallsyms_lookup_name,
1065 },
1066#endif
4b2220f0 1067#ifdef DEBUG_LOG
9ab1ac14 1068 {
79a3bf13 1069 CTL_NAME (CTL_SPL_DEBUG)
9ab1ac14 1070 .procname = "debug",
1071 .mode = 0555,
1072 .child = spl_debug_table,
1073 },
4b2220f0 1074#endif
36b313da 1075 {
79a3bf13 1076 CTL_NAME (CTL_SPL_VM)
36b313da
BB
1077 .procname = "vm",
1078 .mode = 0555,
1079 .child = spl_vm_table,
1080 },
9ab1ac14 1081#ifdef DEBUG_KMEM
1082 {
79a3bf13 1083 CTL_NAME (CTL_SPL_KMEM)
9ab1ac14 1084 .procname = "kmem",
1085 .mode = 0555,
1086 .child = spl_kmem_table,
1087 },
04a479f7 1088#endif
04a479f7 1089 {
79a3bf13 1090 CTL_NAME (CTL_SPL_KSTAT)
04a479f7 1091 .procname = "kstat",
1092 .mode = 0555,
1093 .child = spl_kstat_table,
1094 },
57d1b188 1095 { 0 },
1096};
1097
9ab1ac14 1098static struct ctl_table spl_dir[] = {
57d1b188 1099 {
79a3bf13 1100 CTL_NAME (CTL_SPL)
57d1b188 1101 .procname = "spl",
1102 .mode = 0555,
1103 .child = spl_table,
1104 },
57d86234 1105 { 0 }
1106};
1107
1108static struct ctl_table spl_root[] = {
1109 {
79a3bf13 1110 CTL_NAME (CTL_KERN)
57d86234 1111 .procname = "kernel",
1112 .mode = 0555,
1113 .child = spl_dir,
1114 },
1115 { 0 }
57d1b188 1116};
1117
404992e3 1118static int
1119proc_dir_entry_match(int len, const char *name, struct proc_dir_entry *de)
1120{
1121 if (de->namelen != len)
1122 return 0;
1123
1124 return !memcmp(name, de->name, len);
1125}
1126
04a479f7 1127struct proc_dir_entry *
404992e3 1128proc_dir_entry_find(struct proc_dir_entry *root, const char *str)
1129{
1130 struct proc_dir_entry *de;
1131
1132 for (de = root->subdir; de; de = de->next)
1133 if (proc_dir_entry_match(strlen(str), str, de))
1134 return de;
1135
1136 return NULL;
1137}
1138
04a479f7 1139int
1140proc_dir_entries(struct proc_dir_entry *root)
1141{
1142 struct proc_dir_entry *de;
1143 int i = 0;
1144
1145 for (de = root->subdir; de; de = de->next)
1146 i++;
1147
1148 return i;
1149}
1150
57d1b188 1151int
1114ae6a 1152spl_proc_init(void)
57d1b188 1153{
404992e3 1154 int rc = 0;
b17edc10 1155 SENTRY;
57d1b188 1156
1157#ifdef CONFIG_SYSCTL
57d86234 1158 spl_header = spl_register_sysctl_table(spl_root, 0);
57d1b188 1159 if (spl_header == NULL)
b17edc10 1160 SRETURN(-EUNATCH);
c30df9c8 1161#endif /* CONFIG_SYSCTL */
9ab1ac14 1162
c30df9c8 1163 proc_spl = proc_mkdir("spl", NULL);
1164 if (proc_spl == NULL)
b17edc10 1165 SGOTO(out, rc = -EUNATCH);
404992e3 1166
04a479f7 1167#ifdef DEBUG_KMEM
c30df9c8 1168 proc_spl_kmem = proc_mkdir("kmem", proc_spl);
1169 if (proc_spl_kmem == NULL)
b17edc10 1170 SGOTO(out, rc = -EUNATCH);
ff449ac4 1171
1172 proc_spl_kmem_slab = create_proc_entry("slab", 0444, proc_spl_kmem);
1173 if (proc_spl_kmem_slab == NULL)
b17edc10 1174 SGOTO(out, rc = -EUNATCH);
ff449ac4 1175
1176 proc_spl_kmem_slab->proc_fops = &proc_slab_operations;
04a479f7 1177#endif /* DEBUG_KMEM */
1178
c30df9c8 1179 proc_spl_kstat = proc_mkdir("kstat", proc_spl);
1180 if (proc_spl_kstat == NULL)
b17edc10 1181 SGOTO(out, rc = -EUNATCH);
404992e3 1182out:
c30df9c8 1183 if (rc) {
1184 remove_proc_entry("kstat", proc_spl);
ff449ac4 1185#ifdef DEBUG_KMEM
1186 remove_proc_entry("slab", proc_spl_kmem);
c30df9c8 1187 remove_proc_entry("kmem", proc_spl);
055ffd98 1188#endif
a02118a8 1189 remove_proc_entry("spl", NULL);
c30df9c8 1190#ifdef CONFIG_SYSCTL
1191 spl_unregister_sysctl_table(spl_header);
404992e3 1192#endif /* CONFIG_SYSCTL */
c30df9c8 1193 }
c30df9c8 1194
b17edc10 1195 SRETURN(rc);
57d1b188 1196}
1197
1198void
1114ae6a 1199spl_proc_fini(void)
57d1b188 1200{
b17edc10 1201 SENTRY;
57d1b188 1202
c30df9c8 1203 remove_proc_entry("kstat", proc_spl);
ff449ac4 1204#ifdef DEBUG_KMEM
1205 remove_proc_entry("slab", proc_spl_kmem);
c30df9c8 1206 remove_proc_entry("kmem", proc_spl);
055ffd98 1207#endif
a02118a8 1208 remove_proc_entry("spl", NULL);
c30df9c8 1209
57d1b188 1210#ifdef CONFIG_SYSCTL
1211 ASSERT(spl_header != NULL);
57d86234 1212 spl_unregister_sysctl_table(spl_header);
c30df9c8 1213#endif /* CONFIG_SYSCTL */
1214
b17edc10 1215 SEXIT;
57d1b188 1216}