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