]> git.proxmox.com Git - mirror_spl-debian.git/blame - module/spl/spl-proc.c
Changed z_compress_level() and z_uncompress() prototypes to match the ones in Solaris.
[mirror_spl-debian.git] / module / spl / spl-proc.c
CommitLineData
715f6251 1/*
2 * This file is part of the SPL: Solaris Porting Layer.
3 *
4 * Copyright (c) 2008 Lawrence Livermore National Security, LLC.
5 * Produced at Lawrence Livermore National Laboratory
6 * Written by:
7 * Brian Behlendorf <behlendorf1@llnl.gov>,
8 * Herb Wartens <wartens2@llnl.gov>,
9 * Jim Garlick <garlick@llnl.gov>
10 * UCRL-CODE-235197
11 *
12 * This is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This is distributed in the hope that it will be useful, but WITHOUT
18 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 * for more details.
21 *
22 * You should have received a copy of the GNU General Public License along
23 * with this program; if not, write to the Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 */
26
04a479f7 27#include <sys/proc.h>
57d1b188 28
29#ifdef DEBUG_SUBSYSTEM
30#undef DEBUG_SUBSYSTEM
31#endif
32
33#define DEBUG_SUBSYSTEM S_PROC
34
404992e3 35#ifdef DEBUG_KMEM
57d1b188 36static unsigned long table_min = 0;
37static unsigned long table_max = ~0;
404992e3 38#endif
39
40#ifdef CONFIG_SYSCTL
41static struct ctl_table_header *spl_header = NULL;
c30df9c8 42#endif /* CONFIG_SYSCTL */
43
57d86234 44#if defined(DEBUG_MUTEX) || defined(DEBUG_KMEM) || defined(DEBUG_KSTAT)
c30df9c8 45static struct proc_dir_entry *proc_spl = NULL;
404992e3 46#ifdef DEBUG_MUTEX
c30df9c8 47static struct proc_dir_entry *proc_spl_mutex = NULL;
48static struct proc_dir_entry *proc_spl_mutex_stats = NULL;
49#endif /* DEBUG_MUTEX */
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 */
04a479f7 54#ifdef DEBUG_KSTAT
c30df9c8 55struct proc_dir_entry *proc_spl_kstat = NULL;
56#endif /* DEBUG_KSTAT */
57#endif /* DEBUG_MUTEX || DEBUG_KMEM || DEBUG_KSTAT */
57d1b188 58
57d86234 59#ifdef HAVE_CTL_UNNUMBERED
60
61#define CTL_SPL CTL_UNNUMBERED
62#define CTL_SPL_DEBUG CTL_UNNUMBERED
36b313da 63#define CTL_SPL_VM CTL_UNNUMBERED
57d86234 64#define CTL_SPL_MUTEX CTL_UNNUMBERED
65#define CTL_SPL_KMEM CTL_UNNUMBERED
66#define CTL_SPL_KSTAT CTL_UNNUMBERED
67
68#define CTL_VERSION CTL_UNNUMBERED /* Version */
69#define CTL_HOSTID CTL_UNNUMBERED /* Host id by /usr/bin/hostid */
70#define CTL_HW_SERIAL CTL_UNNUMBERED /* HW serial number by hostid */
71
72#define CTL_DEBUG_SUBSYS CTL_UNNUMBERED /* Debug subsystem */
73#define CTL_DEBUG_MASK CTL_UNNUMBERED /* Debug mask */
74#define CTL_DEBUG_PRINTK CTL_UNNUMBERED /* All messages to console */
75#define CTL_DEBUG_MB CTL_UNNUMBERED /* Debug buffer size */
76#define CTL_DEBUG_BINARY CTL_UNNUMBERED /* Binary data in buffer */
77#define CTL_DEBUG_CATASTROPHE CTL_UNNUMBERED /* Set if BUG'd or panic'd */
78#define CTL_DEBUG_PANIC_ON_BUG CTL_UNNUMBERED /* Should panic on BUG */
79#define CTL_DEBUG_PATH CTL_UNNUMBERED /* Dump log location */
80#define CTL_DEBUG_DUMP CTL_UNNUMBERED /* Dump debug buffer to file */
81#define CTL_DEBUG_FORCE_BUG CTL_UNNUMBERED /* Hook to force a BUG */
82#define CTL_DEBUG_STACK_SIZE CTL_UNNUMBERED /* Max observed stack size */
83
84#define CTL_CONSOLE_RATELIMIT CTL_UNNUMBERED /* Ratelimit console messages */
85#define CTL_CONSOLE_MAX_DELAY_CS CTL_UNNUMBERED /* Max delay skip messages */
86#define CTL_CONSOLE_MIN_DELAY_CS CTL_UNNUMBERED /* Init delay skip messages */
87#define CTL_CONSOLE_BACKOFF CTL_UNNUMBERED /* Delay increase factor */
88
36b313da
BB
89#define CTL_VM_MINFREE CTL_UNNUMBERED /* Minimum free memory */
90#define CTL_VM_DESFREE CTL_UNNUMBERED /* Desired free memory */
91#define CTL_VM_LOTSFREE CTL_UNNUMBERED /* Lots of free memory */
92#define CTL_VM_NEEDFREE CTL_UNNUMBERED /* Need free memory */
93#define CTL_VM_SWAPFS_MINFREE CTL_UNNUMBERED /* Minimum swapfs memory */
36b313da 94#define CTL_VM_SWAPFS_RESERVE CTL_UNNUMBERED /* Reserved swapfs memory */
4ab13d3b
BB
95#define CTL_VM_AVAILRMEM CTL_UNNUMBERED /* Easily available memory */
96#define CTL_VM_FREEMEM CTL_UNNUMBERED /* Free memory */
97#define CTL_VM_PHYSMEM CTL_UNNUMBERED /* Total physical memory */
36b313da 98
57d86234 99#ifdef DEBUG_KMEM
100#define CTL_KMEM_KMEMUSED CTL_UNNUMBERED /* Alloc'd kmem bytes */
101#define CTL_KMEM_KMEMMAX CTL_UNNUMBERED /* Max alloc'd by kmem bytes */
102#define CTL_KMEM_VMEMUSED CTL_UNNUMBERED /* Alloc'd vmem bytes */
103#define CTL_KMEM_VMEMMAX CTL_UNNUMBERED /* Max alloc'd by vmem bytes */
104#define CTL_KMEM_ALLOC_FAILED CTL_UNNUMBERED /* Cache allocations failed */
105#endif
106
107#define CTL_MUTEX_STATS CTL_UNNUMBERED /* Global mutex statistics */
108#define CTL_MUTEX_STATS_PER CTL_UNNUMBERED /* Per mutex statistics */
109#define CTL_MUTEX_SPIN_MAX CTL_UNNUMBERED /* Max mutex spin iterations */
110
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 */
126
127 CTL_DEBUG_SUBSYS, /* Debug subsystem */
128 CTL_DEBUG_MASK, /* Debug mask */
129 CTL_DEBUG_PRINTK, /* Force all messages to console */
130 CTL_DEBUG_MB, /* Debug buffer size */
131 CTL_DEBUG_BINARY, /* Include binary data in buffer */
132 CTL_DEBUG_CATASTROPHE, /* Set if we have BUG'd or panic'd */
133 CTL_DEBUG_PANIC_ON_BUG, /* Set if we should panic on BUG */
134 CTL_DEBUG_PATH, /* Dump log location */
135 CTL_DEBUG_DUMP, /* Dump debug buffer to file */
136 CTL_DEBUG_FORCE_BUG, /* Hook to force a BUG */
137 CTL_DEBUG_STACK_SIZE, /* Max observed stack size */
138
139 CTL_CONSOLE_RATELIMIT, /* Ratelimit console messages */
140 CTL_CONSOLE_MAX_DELAY_CS, /* Max delay which we skip messages */
141 CTL_CONSOLE_MIN_DELAY_CS, /* Init delay which we skip messages */
142 CTL_CONSOLE_BACKOFF, /* Delay increase factor */
143
144 CTL_VM_MINFREE, /* Minimum free memory threshold */
145 CTL_VM_DESFREE, /* Desired free memory threshold */
146 CTL_VM_LOTSFREE, /* Lots of free memory threshold */
147 CTL_VM_NEEDFREE, /* Need free memory deficit */
148 CTL_VM_SWAPFS_MINFREE, /* Minimum swapfs memory */
36b313da 149 CTL_VM_SWAPFS_RESERVE, /* Reserved swapfs memory */
4ab13d3b
BB
150 CTL_VM_AVAILRMEM, /* Easily available memory */
151 CTL_VM_FREEMEM, /* Free memory */
152 CTL_VM_PHYSMEM, /* Total physical memory */
9ab1ac14 153
57d1b188 154#ifdef DEBUG_KMEM
36b313da
BB
155 CTL_KMEM_KMEMUSED, /* Alloc'd kmem bytes */
156 CTL_KMEM_KMEMMAX, /* Max alloc'd by kmem bytes */
157 CTL_KMEM_VMEMUSED, /* Alloc'd vmem bytes */
158 CTL_KMEM_VMEMMAX, /* Max alloc'd by vmem bytes */
57d1b188 159#endif
9ab1ac14 160
36b313da
BB
161 CTL_MUTEX_STATS, /* Global mutex statistics */
162 CTL_MUTEX_STATS_PER, /* Per mutex statistics */
163 CTL_MUTEX_SPIN_MAX, /* Maximum mutex spin iterations */
57d1b188 164};
57d86234 165#endif /* HAVE_CTL_UNNUMBERED */
57d1b188 166
167static int
168proc_copyin_string(char *kbuffer, int kbuffer_size,
169 const char *ubuffer, int ubuffer_size)
170{
171 int size;
172
173 if (ubuffer_size > kbuffer_size)
174 return -EOVERFLOW;
175
176 if (copy_from_user((void *)kbuffer, (void *)ubuffer, ubuffer_size))
177 return -EFAULT;
178
179 /* strip trailing whitespace */
180 size = strnlen(kbuffer, ubuffer_size);
181 while (size-- >= 0)
182 if (!isspace(kbuffer[size]))
183 break;
184
185 /* empty string */
186 if (size < 0)
187 return -EINVAL;
188
189 /* no space to terminate */
190 if (size == kbuffer_size)
191 return -EOVERFLOW;
192
193 kbuffer[size + 1] = 0;
194 return 0;
195}
196
197static int
198proc_copyout_string(char *ubuffer, int ubuffer_size,
199 const char *kbuffer, char *append)
200{
201 /* NB if 'append' != NULL, it's a single character to append to the
202 * copied out string - usually "\n", for /proc entries and
203 * (i.e. a terminating zero byte) for sysctl entries
204 */
205 int size = MIN(strlen(kbuffer), ubuffer_size);
206
207 if (copy_to_user(ubuffer, kbuffer, size))
208 return -EFAULT;
209
210 if (append != NULL && size < ubuffer_size) {
211 if (copy_to_user(ubuffer + size, append, 1))
212 return -EFAULT;
213
214 size++;
215 }
216
217 return size;
218}
219
220static int
221proc_dobitmasks(struct ctl_table *table, int write, struct file *filp,
222 void __user *buffer, size_t *lenp, loff_t *ppos)
223{
224 unsigned long *mask = table->data;
225 int is_subsys = (mask == &spl_debug_subsys) ? 1 : 0;
226 int is_printk = (mask == &spl_debug_printk) ? 1 : 0;
227 int size = 512, rc;
228 char *str;
229 ENTRY;
230
231 str = kmem_alloc(size, KM_SLEEP);
232 if (str == NULL)
233 RETURN(-ENOMEM);
234
235 if (write) {
236 rc = proc_copyin_string(str, size, buffer, *lenp);
237 if (rc < 0)
238 RETURN(rc);
239
240 rc = spl_debug_str2mask(mask, str, is_subsys);
241 /* Always print BUG/ASSERT to console, so keep this mask */
242 if (is_printk)
243 *mask |= D_EMERG;
244
245 *ppos += *lenp;
246 } else {
247 rc = spl_debug_mask2str(str, size, *mask, is_subsys);
248 if (*ppos >= rc)
249 rc = 0;
250 else
251 rc = proc_copyout_string(buffer, *lenp,
252 str + *ppos, "\n");
253 if (rc >= 0) {
254 *lenp = rc;
255 *ppos += rc;
256 }
257 }
258
259 kmem_free(str, size);
260 RETURN(rc);
261}
262
263static int
264proc_debug_mb(struct ctl_table *table, int write, struct file *filp,
265 void __user *buffer, size_t *lenp, loff_t *ppos)
266{
267 char str[32];
268 int rc, len;
269 ENTRY;
270
271 if (write) {
272 rc = proc_copyin_string(str, sizeof(str), buffer, *lenp);
273 if (rc < 0)
274 RETURN(rc);
275
276 rc = spl_debug_set_mb(simple_strtoul(str, NULL, 0));
277 *ppos += *lenp;
278 } else {
279 len = snprintf(str, sizeof(str), "%d", spl_debug_get_mb());
280 if (*ppos >= len)
281 rc = 0;
282 else
283 rc = proc_copyout_string(buffer, *lenp, str + *ppos, "\n");
284
285 if (rc >= 0) {
286 *lenp = rc;
287 *ppos += rc;
288 }
289 }
290
291 RETURN(rc);
292}
293
294static int
295proc_dump_kernel(struct ctl_table *table, int write, struct file *filp,
296 void __user *buffer, size_t *lenp, loff_t *ppos)
297{
298 ENTRY;
299
300 if (write) {
7fea96c0 301 spl_debug_dumplog(0);
57d1b188 302 *ppos += *lenp;
303 } else {
304 *lenp = 0;
305 }
306
307 RETURN(0);
308}
309
310static int
311proc_force_bug(struct ctl_table *table, int write, struct file *filp,
312 void __user *buffer, size_t *lenp, loff_t *ppos)
313{
314 ENTRY;
315
316 if (write) {
2fae1b3d 317 CERROR("Crashing due to forced SBUG\n");
318 SBUG();
57d1b188 319 /* Unreachable */
320 } else {
321 *lenp = 0;
322 }
323
324 RETURN(0);
325}
326
327static int
328proc_console_max_delay_cs(struct ctl_table *table, int write, struct file *filp,
329 void __user *buffer, size_t *lenp, loff_t *ppos)
330{
331 int rc, max_delay_cs;
332 struct ctl_table dummy = *table;
333 long d;
334 ENTRY;
335
336 dummy.data = &max_delay_cs;
337 dummy.proc_handler = &proc_dointvec;
338
339 if (write) {
340 max_delay_cs = 0;
341 rc = proc_dointvec(&dummy, write, filp, buffer, lenp, ppos);
342 if (rc < 0)
343 RETURN(rc);
344
345 if (max_delay_cs <= 0)
346 RETURN(-EINVAL);
347
348 d = (max_delay_cs * HZ) / 100;
349 if (d == 0 || d < spl_console_min_delay)
350 RETURN(-EINVAL);
351
352 spl_console_max_delay = d;
353 } else {
354 max_delay_cs = (spl_console_max_delay * 100) / HZ;
355 rc = proc_dointvec(&dummy, write, filp, buffer, lenp, ppos);
356 }
357
358 RETURN(rc);
359}
360
361static int
362proc_console_min_delay_cs(struct ctl_table *table, int write, struct file *filp,
363 void __user *buffer, size_t *lenp, loff_t *ppos)
364{
365 int rc, min_delay_cs;
366 struct ctl_table dummy = *table;
367 long d;
368 ENTRY;
369
370 dummy.data = &min_delay_cs;
371 dummy.proc_handler = &proc_dointvec;
372
373 if (write) {
374 min_delay_cs = 0;
375 rc = proc_dointvec(&dummy, write, filp, buffer, lenp, ppos);
376 if (rc < 0)
377 RETURN(rc);
378
379 if (min_delay_cs <= 0)
380 RETURN(-EINVAL);
381
382 d = (min_delay_cs * HZ) / 100;
383 if (d == 0 || d > spl_console_max_delay)
384 RETURN(-EINVAL);
385
386 spl_console_min_delay = d;
387 } else {
388 min_delay_cs = (spl_console_min_delay * 100) / HZ;
389 rc = proc_dointvec(&dummy, write, filp, buffer, lenp, ppos);
390 }
391
392 RETURN(rc);
393}
394
395static int
396proc_console_backoff(struct ctl_table *table, int write, struct file *filp,
397 void __user *buffer, size_t *lenp, loff_t *ppos)
398{
399 int rc, backoff;
400 struct ctl_table dummy = *table;
401 ENTRY;
402
403 dummy.data = &backoff;
404 dummy.proc_handler = &proc_dointvec;
405
406 if (write) {
407 backoff = 0;
408 rc = proc_dointvec(&dummy, write, filp, buffer, lenp, ppos);
409 if (rc < 0)
410 RETURN(rc);
411
412 if (backoff <= 0)
413 RETURN(-EINVAL);
414
415 spl_console_backoff = backoff;
416 } else {
417 backoff = spl_console_backoff;
418 rc = proc_dointvec(&dummy, write, filp, buffer, lenp, ppos);
419 }
420
421 RETURN(rc);
422}
423
c6dc93d6 424#ifdef DEBUG_KMEM
57d1b188 425static int
426proc_doatomic64(struct ctl_table *table, int write, struct file *filp,
427 void __user *buffer, size_t *lenp, loff_t *ppos)
428{
429 int rc = 0;
430 unsigned long min = 0, max = ~0, val;
431 struct ctl_table dummy = *table;
432 ENTRY;
433
434 dummy.data = &val;
435 dummy.proc_handler = &proc_dointvec;
436 dummy.extra1 = &min;
437 dummy.extra2 = &max;
438
439 if (write) {
440 *ppos += *lenp;
441 } else {
550f1705 442 val = atomic64_read((atomic64_t *)table->data);
57d1b188 443 rc = proc_doulongvec_minmax(&dummy, write, filp,
444 buffer, lenp, ppos);
445 }
446
447 RETURN(rc);
448}
c6dc93d6 449#endif /* DEBUG_KMEM */
57d1b188 450
451static int
452proc_dohostid(struct ctl_table *table, int write, struct file *filp,
453 void __user *buffer, size_t *lenp, loff_t *ppos)
454{
455 int len, rc = 0;
937879f1 456 int32_t val;
57d1b188 457 char *end, str[32];
458 ENTRY;
459
460 if (write) {
461 /* We can't use proc_doulongvec_minmax() in the write
462 * case hear because hostid while a hex value has no
463 * leading 0x which confuses the helper function. */
464 rc = proc_copyin_string(str, sizeof(str), buffer, *lenp);
465 if (rc < 0)
466 RETURN(rc);
467
937879f1 468 val = simple_strtol(str, &end, 16);
57d1b188 469 if (str == end)
470 RETURN(-EINVAL);
471
937879f1 472 spl_hostid = (long)val;
99639e4a
BB
473 (void)snprintf(hw_serial, HW_HOSTID_LEN-1, "%u",
474 (val >= 0) ? val : -val);
57d1b188 475 *ppos += *lenp;
476 } else {
477 len = snprintf(str, sizeof(str), "%lx", spl_hostid);
478 if (*ppos >= len)
479 rc = 0;
480 else
481 rc = proc_copyout_string(buffer, *lenp, str + *ppos, "\n");
482
483 if (rc >= 0) {
484 *lenp = rc;
485 *ppos += rc;
486 }
487 }
488
489 RETURN(rc);
490}
491
4ab13d3b
BB
492static int
493proc_doavailrmem(struct ctl_table *table, int write, struct file *filp,
494 void __user *buffer, size_t *lenp, loff_t *ppos)
495{
496 int len, rc = 0;
497 char str[32];
498 ENTRY;
499
500 if (write) {
501 *ppos += *lenp;
502 } else {
503 len = snprintf(str, sizeof(str), "%lu", (unsigned long)availrmem);
504 if (*ppos >= len)
505 rc = 0;
506 else
507 rc = proc_copyout_string(buffer, *lenp, str + *ppos, "\n");
508
509 if (rc >= 0) {
510 *lenp = rc;
511 *ppos += rc;
512 }
513 }
514
515 RETURN(rc);
516}
517
518static int
519proc_dofreemem(struct ctl_table *table, int write, struct file *filp,
520 void __user *buffer, size_t *lenp, loff_t *ppos)
521{
522 int len, rc = 0;
523 char str[32];
524 ENTRY;
525
526 if (write) {
527 *ppos += *lenp;
528 } else {
529 len = snprintf(str, sizeof(str), "%lu", (unsigned long)freemem);
530 if (*ppos >= len)
531 rc = 0;
532 else
533 rc = proc_copyout_string(buffer, *lenp, str + *ppos, "\n");
534
535 if (rc >= 0) {
536 *lenp = rc;
537 *ppos += rc;
538 }
539 }
540
541 RETURN(rc);
542}
543
9ab1ac14 544#ifdef DEBUG_MUTEX
545static void
546mutex_seq_show_headers(struct seq_file *f)
547{
548 seq_printf(f, "%-36s %-4s %-16s\t"
549 "e_tot\te_nh\te_sp\te_sl\tte_tot\tte_nh\n",
550 "name", "type", "owner");
551}
552
553static int
554mutex_seq_show(struct seq_file *f, void *p)
555{
556 kmutex_t *mp = p;
557 char t = 'X';
558 int i;
559
560 ASSERT(mp->km_magic == KM_MAGIC);
561
562 switch (mp->km_type) {
563 case MUTEX_DEFAULT: t = 'D'; break;
564 case MUTEX_SPIN: t = 'S'; break;
565 case MUTEX_ADAPTIVE: t = 'A'; break;
566 default:
567 SBUG();
568 }
569 seq_printf(f, "%-36s %c ", mp->km_name, t);
570 if (mp->km_owner)
571 seq_printf(f, "%p\t", mp->km_owner);
572 else
573 seq_printf(f, "%-16s\t", "<not held>");
574
575 for (i = 0; i < MUTEX_STATS_SIZE; i++)
576 seq_printf(f, "%d%c", mp->km_stats[i],
577 (i + 1 == MUTEX_STATS_SIZE) ? '\n' : '\t');
578
579 return 0;
580}
581
582static void *
583mutex_seq_start(struct seq_file *f, loff_t *pos)
584{
585 struct list_head *p;
586 loff_t n = *pos;
587 ENTRY;
588
404992e3 589 spin_lock(&mutex_stats_lock);
9ab1ac14 590 if (!n)
591 mutex_seq_show_headers(f);
592
593 p = mutex_stats_list.next;
594 while (n--) {
595 p = p->next;
596 if (p == &mutex_stats_list)
597 RETURN(NULL);
598 }
599
600 RETURN(list_entry(p, kmutex_t, km_list));
601}
602
603static void *
604mutex_seq_next(struct seq_file *f, void *p, loff_t *pos)
605{
606 kmutex_t *mp = p;
607 ENTRY;
608
609 ++*pos;
610 RETURN((mp->km_list.next == &mutex_stats_list) ?
611 NULL : list_entry(mp->km_list.next, kmutex_t, km_list));
612}
613
614static void
615mutex_seq_stop(struct seq_file *f, void *v)
616{
404992e3 617 spin_unlock(&mutex_stats_lock);
9ab1ac14 618}
619
620static struct seq_operations mutex_seq_ops = {
621 .show = mutex_seq_show,
622 .start = mutex_seq_start,
623 .next = mutex_seq_next,
624 .stop = mutex_seq_stop,
625};
626
627static int
628proc_mutex_open(struct inode *inode, struct file *filp)
629{
630 return seq_open(filp, &mutex_seq_ops);
631}
632
633static struct file_operations proc_mutex_operations = {
634 .open = proc_mutex_open,
635 .read = seq_read,
636 .llseek = seq_lseek,
637 .release = seq_release,
638};
639#endif /* DEBUG_MUTEX */
640
ff449ac4 641#ifdef DEBUG_KMEM
642static void
643slab_seq_show_headers(struct seq_file *f)
644{
645 seq_printf(f, "%-36s\n", "name");
646}
647
648static int
649slab_seq_show(struct seq_file *f, void *p)
650{
651 spl_kmem_cache_t *skc = p;
652
653 ASSERT(skc->skc_magic == SKC_MAGIC);
654
655 spin_lock(&skc->skc_lock);
656 seq_printf(f, "%-36s ", skc->skc_name);
a1502d76 657 seq_printf(f, "%u %u %u - %lu %lu %lu - %lu %lu %lu - %lu %lu %lu\n",
ff449ac4 658 (unsigned)skc->skc_obj_size,
a1502d76 659 (unsigned)skc->skc_slab_objs,
ff449ac4 660 (unsigned)skc->skc_slab_size,
ff449ac4 661 (long unsigned)skc->skc_slab_fail,
662 (long unsigned)skc->skc_slab_create,
663 (long unsigned)skc->skc_slab_destroy,
664 (long unsigned)skc->skc_slab_total,
665 (long unsigned)skc->skc_slab_alloc,
666 (long unsigned)skc->skc_slab_max,
667 (long unsigned)skc->skc_obj_total,
668 (long unsigned)skc->skc_obj_alloc,
a1502d76 669 (long unsigned)skc->skc_obj_max);
ff449ac4 670
671 spin_unlock(&skc->skc_lock);
672
673 return 0;
674}
675
676static void *
677slab_seq_start(struct seq_file *f, loff_t *pos)
678{
679 struct list_head *p;
680 loff_t n = *pos;
681 ENTRY;
682
683 down_read(&spl_kmem_cache_sem);
684 if (!n)
685 slab_seq_show_headers(f);
686
687 p = spl_kmem_cache_list.next;
688 while (n--) {
689 p = p->next;
690 if (p == &spl_kmem_cache_list)
691 RETURN(NULL);
692 }
693
694 RETURN(list_entry(p, spl_kmem_cache_t, skc_list));
695}
696
697static void *
698slab_seq_next(struct seq_file *f, void *p, loff_t *pos)
699{
700 spl_kmem_cache_t *skc = p;
701 ENTRY;
702
703 ++*pos;
704 RETURN((skc->skc_list.next == &spl_kmem_cache_list) ?
705 NULL : list_entry(skc->skc_list.next, spl_kmem_cache_t, skc_list));
706}
707
708static void
709slab_seq_stop(struct seq_file *f, void *v)
710{
711 up_read(&spl_kmem_cache_sem);
712}
713
714static struct seq_operations slab_seq_ops = {
715 .show = slab_seq_show,
716 .start = slab_seq_start,
717 .next = slab_seq_next,
718 .stop = slab_seq_stop,
719};
720
721static int
722proc_slab_open(struct inode *inode, struct file *filp)
723{
724 return seq_open(filp, &slab_seq_ops);
725}
726
727static struct file_operations proc_slab_operations = {
728 .open = proc_slab_open,
729 .read = seq_read,
730 .llseek = seq_lseek,
731 .release = seq_release,
732};
733#endif /* DEBUG_KMEM */
734
9ab1ac14 735static struct ctl_table spl_debug_table[] = {
57d1b188 736 {
737 .ctl_name = CTL_DEBUG_SUBSYS,
9ab1ac14 738 .procname = "subsystem",
57d1b188 739 .data = &spl_debug_subsys,
740 .maxlen = sizeof(unsigned long),
741 .mode = 0644,
742 .proc_handler = &proc_dobitmasks
743 },
744 {
745 .ctl_name = CTL_DEBUG_MASK,
9ab1ac14 746 .procname = "mask",
57d1b188 747 .data = &spl_debug_mask,
748 .maxlen = sizeof(unsigned long),
749 .mode = 0644,
750 .proc_handler = &proc_dobitmasks
751 },
752 {
753 .ctl_name = CTL_DEBUG_PRINTK,
9ab1ac14 754 .procname = "printk",
57d1b188 755 .data = &spl_debug_printk,
756 .maxlen = sizeof(unsigned long),
757 .mode = 0644,
758 .proc_handler = &proc_dobitmasks
759 },
760 {
761 .ctl_name = CTL_DEBUG_MB,
9ab1ac14 762 .procname = "mb",
57d1b188 763 .mode = 0644,
764 .proc_handler = &proc_debug_mb,
765 },
766 {
767 .ctl_name = CTL_DEBUG_BINARY,
9ab1ac14 768 .procname = "binary",
57d1b188 769 .data = &spl_debug_binary,
770 .maxlen = sizeof(int),
771 .mode = 0644,
772 .proc_handler = &proc_dointvec,
773 },
774 {
775 .ctl_name = CTL_DEBUG_CATASTROPHE,
776 .procname = "catastrophe",
777 .data = &spl_debug_catastrophe,
778 .maxlen = sizeof(int),
779 .mode = 0444,
780 .proc_handler = &proc_dointvec,
781 },
782 {
783 .ctl_name = CTL_DEBUG_PANIC_ON_BUG,
784 .procname = "panic_on_bug",
785 .data = &spl_debug_panic_on_bug,
786 .maxlen = sizeof(int),
787 .mode = 0644,
788 .proc_handler = &proc_dointvec
789 },
790 {
791 .ctl_name = CTL_DEBUG_PATH,
9ab1ac14 792 .procname = "path",
57d1b188 793 .data = spl_debug_file_path,
794 .maxlen = sizeof(spl_debug_file_path),
795 .mode = 0644,
796 .proc_handler = &proc_dostring,
797 },
798 {
799 .ctl_name = CTL_DEBUG_DUMP,
9ab1ac14 800 .procname = "dump",
57d1b188 801 .mode = 0200,
802 .proc_handler = &proc_dump_kernel,
803 },
804 { .ctl_name = CTL_DEBUG_FORCE_BUG,
805 .procname = "force_bug",
806 .mode = 0200,
807 .proc_handler = &proc_force_bug,
808 },
809 {
810 .ctl_name = CTL_CONSOLE_RATELIMIT,
811 .procname = "console_ratelimit",
812 .data = &spl_console_ratelimit,
813 .maxlen = sizeof(int),
814 .mode = 0644,
815 .proc_handler = &proc_dointvec,
816 },
817 {
818 .ctl_name = CTL_CONSOLE_MAX_DELAY_CS,
819 .procname = "console_max_delay_centisecs",
820 .maxlen = sizeof(int),
821 .mode = 0644,
822 .proc_handler = &proc_console_max_delay_cs,
823 },
824 {
825 .ctl_name = CTL_CONSOLE_MIN_DELAY_CS,
826 .procname = "console_min_delay_centisecs",
827 .maxlen = sizeof(int),
828 .mode = 0644,
829 .proc_handler = &proc_console_min_delay_cs,
830 },
831 {
832 .ctl_name = CTL_CONSOLE_BACKOFF,
833 .procname = "console_backoff",
834 .maxlen = sizeof(int),
835 .mode = 0644,
836 .proc_handler = &proc_console_backoff,
837 },
838 {
9ab1ac14 839 .ctl_name = CTL_DEBUG_STACK_SIZE,
57d1b188 840 .procname = "stack_max",
841 .data = &spl_debug_stack,
842 .maxlen = sizeof(int),
843 .mode = 0444,
844 .proc_handler = &proc_dointvec,
845 },
9ab1ac14 846 {0},
847};
848
36b313da
BB
849static struct ctl_table spl_vm_table[] = {
850 {
851 .ctl_name = CTL_VM_MINFREE,
852 .procname = "minfree",
853 .data = &minfree,
854 .maxlen = sizeof(int),
855 .mode = 0644,
856 .proc_handler = &proc_dointvec,
857 },
858 {
859 .ctl_name = CTL_VM_DESFREE,
860 .procname = "desfree",
861 .data = &desfree,
862 .maxlen = sizeof(int),
863 .mode = 0644,
864 .proc_handler = &proc_dointvec,
865 },
866 {
867 .ctl_name = CTL_VM_LOTSFREE,
868 .procname = "lotsfree",
869 .data = &lotsfree,
870 .maxlen = sizeof(int),
871 .mode = 0644,
872 .proc_handler = &proc_dointvec,
873 },
874 {
875 .ctl_name = CTL_VM_NEEDFREE,
876 .procname = "needfree",
877 .data = &needfree,
878 .maxlen = sizeof(int),
879 .mode = 0444,
880 .proc_handler = &proc_dointvec,
881 },
882 {
883 .ctl_name = CTL_VM_SWAPFS_MINFREE,
884 .procname = "swapfs_minfree",
885 .data = &swapfs_minfree,
886 .maxlen = sizeof(int),
887 .mode = 0644,
888 .proc_handler = &proc_dointvec,
889 },
36b313da
BB
890 {
891 .ctl_name = CTL_VM_SWAPFS_RESERVE,
892 .procname = "swapfs_reserve",
893 .data = &swapfs_reserve,
894 .maxlen = sizeof(int),
895 .mode = 0644,
896 .proc_handler = &proc_dointvec,
897 },
898 {
899 .ctl_name = CTL_VM_AVAILRMEM,
900 .procname = "availrmem",
4ab13d3b
BB
901 .mode = 0444,
902 .proc_handler = &proc_doavailrmem,
903 },
904 {
905 .ctl_name = CTL_VM_FREEMEM,
906 .procname = "freemem",
907 .data = (void *)2,
908 .maxlen = sizeof(int),
909 .mode = 0444,
910 .proc_handler = &proc_dofreemem,
911 },
912 {
913 .ctl_name = CTL_VM_PHYSMEM,
914 .procname = "physmem",
915 .data = &physmem,
36b313da
BB
916 .maxlen = sizeof(int),
917 .mode = 0444,
918 .proc_handler = &proc_dointvec,
919 },
920 {0},
921};
922
9ab1ac14 923#ifdef DEBUG_MUTEX
924static struct ctl_table spl_mutex_table[] = {
925 {
926 .ctl_name = CTL_MUTEX_STATS,
927 .procname = "stats",
928 .data = &mutex_stats,
929 .maxlen = sizeof(int) * MUTEX_STATS_SIZE,
930 .mode = 0444,
931 .proc_handler = &proc_dointvec,
932 },
933 {
934 .ctl_name = CTL_MUTEX_SPIN_MAX,
935 .procname = "spin_max",
936 .data = &mutex_spin_max,
937 .maxlen = sizeof(int),
938 .mode = 0644,
939 .proc_handler = &proc_dointvec,
940 },
941 {0},
942};
943#endif /* DEBUG_MUTEX */
944
57d1b188 945#ifdef DEBUG_KMEM
9ab1ac14 946static struct ctl_table spl_kmem_table[] = {
57d1b188 947 {
948 .ctl_name = CTL_KMEM_KMEMUSED,
949 .procname = "kmem_used",
950 .data = &kmem_alloc_used,
951 .maxlen = sizeof(atomic64_t),
952 .mode = 0444,
953 .proc_handler = &proc_doatomic64,
954 },
955 {
956 .ctl_name = CTL_KMEM_KMEMMAX,
957 .procname = "kmem_max",
958 .data = &kmem_alloc_max,
959 .maxlen = sizeof(unsigned long),
960 .extra1 = &table_min,
961 .extra2 = &table_max,
962 .mode = 0444,
963 .proc_handler = &proc_doulongvec_minmax,
964 },
965 {
966 .ctl_name = CTL_KMEM_VMEMUSED,
967 .procname = "vmem_used",
968 .data = &vmem_alloc_used,
969 .maxlen = sizeof(atomic64_t),
970 .mode = 0444,
971 .proc_handler = &proc_doatomic64,
972 },
973 {
974 .ctl_name = CTL_KMEM_VMEMMAX,
975 .procname = "vmem_max",
976 .data = &vmem_alloc_max,
977 .maxlen = sizeof(unsigned long),
978 .extra1 = &table_min,
979 .extra2 = &table_max,
980 .mode = 0444,
981 .proc_handler = &proc_doulongvec_minmax,
982 },
9ab1ac14 983 {0},
984};
04a479f7 985#endif /* DEBUG_KMEM */
986
987#ifdef DEBUG_KSTAT
988static struct ctl_table spl_kstat_table[] = {
989 {0},
990};
991#endif /* DEBUG_KSTAT */
9ab1ac14 992
993static struct ctl_table spl_table[] = {
994 /* NB No .strategy entries have been provided since
995 * sysctl(8) prefers to go via /proc for portability.
996 */
997 {
998 .ctl_name = CTL_VERSION,
999 .procname = "version",
1000 .data = spl_version,
1001 .maxlen = sizeof(spl_version),
1002 .mode = 0444,
1003 .proc_handler = &proc_dostring,
1004 },
57d1b188 1005 {
1006 .ctl_name = CTL_HOSTID,
1007 .procname = "hostid",
1008 .data = &spl_hostid,
1009 .maxlen = sizeof(unsigned long),
1010 .mode = 0644,
1011 .proc_handler = &proc_dohostid,
1012 },
1013 {
1014 .ctl_name = CTL_HW_SERIAL,
1015 .procname = "hw_serial",
937879f1 1016 .data = hw_serial,
1017 .maxlen = sizeof(hw_serial),
57d1b188 1018 .mode = 0444,
1019 .proc_handler = &proc_dostring,
1020 },
9ab1ac14 1021 {
1022 .ctl_name = CTL_SPL_DEBUG,
1023 .procname = "debug",
1024 .mode = 0555,
1025 .child = spl_debug_table,
1026 },
36b313da
BB
1027 {
1028 .ctl_name = CTL_SPL_VM,
1029 .procname = "vm",
1030 .mode = 0555,
1031 .child = spl_vm_table,
1032 },
9ab1ac14 1033#ifdef DEBUG_MUTEX
1034 {
1035 .ctl_name = CTL_SPL_MUTEX,
1036 .procname = "mutex",
1037 .mode = 0555,
1038 .child = spl_mutex_table,
1039 },
1040#endif
1041#ifdef DEBUG_KMEM
1042 {
1043 .ctl_name = CTL_SPL_KMEM,
1044 .procname = "kmem",
1045 .mode = 0555,
1046 .child = spl_kmem_table,
1047 },
04a479f7 1048#endif
1049#ifdef DEBUG_KSTAT
1050 {
1051 .ctl_name = CTL_SPL_KSTAT,
1052 .procname = "kstat",
1053 .mode = 0555,
1054 .child = spl_kstat_table,
1055 },
9ab1ac14 1056#endif
57d1b188 1057 { 0 },
1058};
1059
9ab1ac14 1060static struct ctl_table spl_dir[] = {
57d1b188 1061 {
1062 .ctl_name = CTL_SPL,
1063 .procname = "spl",
1064 .mode = 0555,
1065 .child = spl_table,
1066 },
57d86234 1067 { 0 }
1068};
1069
1070static struct ctl_table spl_root[] = {
1071 {
1072 .ctl_name = CTL_KERN,
1073 .procname = "kernel",
1074 .mode = 0555,
1075 .child = spl_dir,
1076 },
1077 { 0 }
57d1b188 1078};
1079
404992e3 1080static int
1081proc_dir_entry_match(int len, const char *name, struct proc_dir_entry *de)
1082{
1083 if (de->namelen != len)
1084 return 0;
1085
1086 return !memcmp(name, de->name, len);
1087}
1088
04a479f7 1089struct proc_dir_entry *
404992e3 1090proc_dir_entry_find(struct proc_dir_entry *root, const char *str)
1091{
1092 struct proc_dir_entry *de;
1093
1094 for (de = root->subdir; de; de = de->next)
1095 if (proc_dir_entry_match(strlen(str), str, de))
1096 return de;
1097
1098 return NULL;
1099}
1100
04a479f7 1101int
1102proc_dir_entries(struct proc_dir_entry *root)
1103{
1104 struct proc_dir_entry *de;
1105 int i = 0;
1106
1107 for (de = root->subdir; de; de = de->next)
1108 i++;
1109
1110 return i;
1111}
1112
57d1b188 1113int
1114proc_init(void)
1115{
404992e3 1116 int rc = 0;
57d1b188 1117 ENTRY;
1118
1119#ifdef CONFIG_SYSCTL
57d86234 1120 spl_header = spl_register_sysctl_table(spl_root, 0);
57d1b188 1121 if (spl_header == NULL)
1122 RETURN(-EUNATCH);
c30df9c8 1123#endif /* CONFIG_SYSCTL */
9ab1ac14 1124
57d86234 1125#if defined(DEBUG_MUTEX) || defined(DEBUG_KMEM) || defined(DEBUG_KSTAT)
c30df9c8 1126 proc_spl = proc_mkdir("spl", NULL);
1127 if (proc_spl == NULL)
404992e3 1128 GOTO(out, rc = -EUNATCH);
1129
9ab1ac14 1130#ifdef DEBUG_MUTEX
c30df9c8 1131 proc_spl_mutex = proc_mkdir("mutex", proc_spl);
1132 if (proc_spl_mutex == NULL)
404992e3 1133 GOTO(out, rc = -EUNATCH);
1134
c30df9c8 1135 proc_spl_mutex_stats = create_proc_entry("stats_per", 0444,
1136 proc_spl_mutex);
1137 if (proc_spl_mutex_stats == NULL)
404992e3 1138 GOTO(out, rc = -EUNATCH);
1139
c30df9c8 1140 proc_spl_mutex_stats->proc_fops = &proc_mutex_operations;
9ab1ac14 1141#endif /* DEBUG_MUTEX */
04a479f7 1142
1143#ifdef DEBUG_KMEM
c30df9c8 1144 proc_spl_kmem = proc_mkdir("kmem", proc_spl);
1145 if (proc_spl_kmem == NULL)
1146 GOTO(out, rc = -EUNATCH);
ff449ac4 1147
1148 proc_spl_kmem_slab = create_proc_entry("slab", 0444, proc_spl_kmem);
1149 if (proc_spl_kmem_slab == NULL)
1150 GOTO(out, rc = -EUNATCH);
1151
1152 proc_spl_kmem_slab->proc_fops = &proc_slab_operations;
04a479f7 1153#endif /* DEBUG_KMEM */
1154
1155#ifdef DEBUG_KSTAT
c30df9c8 1156 proc_spl_kstat = proc_mkdir("kstat", proc_spl);
1157 if (proc_spl_kstat == NULL)
1158 GOTO(out, rc = -EUNATCH);
04a479f7 1159#endif /* DEBUG_KSTAT */
1160
404992e3 1161out:
c30df9c8 1162 if (rc) {
1163 remove_proc_entry("kstat", proc_spl);
ff449ac4 1164#ifdef DEBUG_KMEM
1165 remove_proc_entry("slab", proc_spl_kmem);
1166#endif
c30df9c8 1167 remove_proc_entry("kmem", proc_spl);
4afaaefa 1168#ifdef DEBUG_MUTEX
c30df9c8 1169 remove_proc_entry("stats_per", proc_spl_mutex);
4afaaefa 1170#endif
c30df9c8 1171 remove_proc_entry("mutex", proc_spl);
a02118a8 1172 remove_proc_entry("spl", NULL);
c30df9c8 1173#ifdef CONFIG_SYSCTL
1174 spl_unregister_sysctl_table(spl_header);
404992e3 1175#endif /* CONFIG_SYSCTL */
c30df9c8 1176 }
1177#endif /* DEBUG_MUTEX || DEBUG_KMEM || DEBUG_KSTAT */
1178
404992e3 1179 RETURN(rc);
57d1b188 1180}
1181
1182void
1183proc_fini(void)
1184{
1185 ENTRY;
1186
c30df9c8 1187#if defined(DEBUG_MUTEX) || defined(DEBUG_KMEM) || defined(DEBUG_KSTAT)
1188 remove_proc_entry("kstat", proc_spl);
ff449ac4 1189#ifdef DEBUG_KMEM
1190 remove_proc_entry("slab", proc_spl_kmem);
1191#endif
c30df9c8 1192 remove_proc_entry("kmem", proc_spl);
4afaaefa 1193#ifdef DEBUG_MUTEX
c30df9c8 1194 remove_proc_entry("stats_per", proc_spl_mutex);
4afaaefa 1195#endif
c30df9c8 1196 remove_proc_entry("mutex", proc_spl);
a02118a8 1197 remove_proc_entry("spl", NULL);
c30df9c8 1198#endif /* DEBUG_MUTEX || DEBUG_KMEM || DEBUG_KSTAT */
1199
57d1b188 1200#ifdef CONFIG_SYSCTL
1201 ASSERT(spl_header != NULL);
57d86234 1202 spl_unregister_sysctl_table(spl_header);
c30df9c8 1203#endif /* CONFIG_SYSCTL */
1204
57d1b188 1205 EXIT;
1206}