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