1 #include <linux/proc_fs.h>
2 #include <linux/kmod.h>
3 #include <linux/uaccess.h>
4 #include <linux/ctype.h>
5 #include <linux/sysctl.h>
6 #include <sys/sysmacros.h>
11 #ifdef DEBUG_SUBSYSTEM
12 #undef DEBUG_SUBSYSTEM
15 #define DEBUG_SUBSYSTEM S_PROC
17 static struct ctl_table_header
*spl_header
= NULL
;
18 static unsigned long table_min
= 0;
19 static unsigned long table_max
= ~0;
23 CTL_DEBUG_SUBSYS
= 1, /* Debug subsystem */
24 CTL_DEBUG_MASK
, /* Debug mask */
25 CTL_DEBUG_PRINTK
, /* Force all messages to console */
26 CTL_DEBUG_MB
, /* Debug buffer size */
27 CTL_DEBUG_BINARY
, /* Include binary data in buffer */
28 CTL_DEBUG_CATASTROPHE
, /* Set if we have BUG'd or panic'd */
29 CTL_DEBUG_PANIC_ON_BUG
, /* Set if we should panic on BUG */
30 CTL_DEBUG_PATH
, /* Dump log location */
31 CTL_DEBUG_DUMP
, /* Dump debug buffer to file */
32 CTL_DEBUG_FORCE_BUG
, /* Hook to force a BUG */
33 CTL_CONSOLE_RATELIMIT
, /* Ratelimit console messages */
34 CTL_CONSOLE_MAX_DELAY_CS
, /* Max delay at which we skip messages */
35 CTL_CONSOLE_MIN_DELAY_CS
, /* Init delay at which we skip messages */
36 CTL_CONSOLE_BACKOFF
, /* Delay increase factor */
37 CTL_STACK_SIZE
, /* Max observed stack size */
39 CTL_KMEM_KMEMUSED
, /* Crrently alloc'd kmem bytes */
40 CTL_KMEM_KMEMMAX
, /* Max alloc'd by kmem bytes */
41 CTL_KMEM_VMEMUSED
, /* Currently alloc'd vmem bytes */
42 CTL_KMEM_VMEMMAX
, /* Max alloc'd by vmem bytes */
44 CTL_HOSTID
, /* Host id reported by /usr/bin/hostid */
45 CTL_HW_SERIAL
, /* Hardware serial number from hostid */
49 proc_copyin_string(char *kbuffer
, int kbuffer_size
,
50 const char *ubuffer
, int ubuffer_size
)
54 if (ubuffer_size
> kbuffer_size
)
57 if (copy_from_user((void *)kbuffer
, (void *)ubuffer
, ubuffer_size
))
60 /* strip trailing whitespace */
61 size
= strnlen(kbuffer
, ubuffer_size
);
63 if (!isspace(kbuffer
[size
]))
70 /* no space to terminate */
71 if (size
== kbuffer_size
)
74 kbuffer
[size
+ 1] = 0;
79 proc_copyout_string(char *ubuffer
, int ubuffer_size
,
80 const char *kbuffer
, char *append
)
82 /* NB if 'append' != NULL, it's a single character to append to the
83 * copied out string - usually "\n", for /proc entries and
84 * (i.e. a terminating zero byte) for sysctl entries
86 int size
= MIN(strlen(kbuffer
), ubuffer_size
);
88 if (copy_to_user(ubuffer
, kbuffer
, size
))
91 if (append
!= NULL
&& size
< ubuffer_size
) {
92 if (copy_to_user(ubuffer
+ size
, append
, 1))
102 proc_dobitmasks(struct ctl_table
*table
, int write
, struct file
*filp
,
103 void __user
*buffer
, size_t *lenp
, loff_t
*ppos
)
105 unsigned long *mask
= table
->data
;
106 int is_subsys
= (mask
== &spl_debug_subsys
) ? 1 : 0;
107 int is_printk
= (mask
== &spl_debug_printk
) ? 1 : 0;
112 str
= kmem_alloc(size
, KM_SLEEP
);
117 rc
= proc_copyin_string(str
, size
, buffer
, *lenp
);
121 rc
= spl_debug_str2mask(mask
, str
, is_subsys
);
122 /* Always print BUG/ASSERT to console, so keep this mask */
128 rc
= spl_debug_mask2str(str
, size
, *mask
, is_subsys
);
132 rc
= proc_copyout_string(buffer
, *lenp
,
140 kmem_free(str
, size
);
145 proc_debug_mb(struct ctl_table
*table
, int write
, struct file
*filp
,
146 void __user
*buffer
, size_t *lenp
, loff_t
*ppos
)
153 rc
= proc_copyin_string(str
, sizeof(str
), buffer
, *lenp
);
157 rc
= spl_debug_set_mb(simple_strtoul(str
, NULL
, 0));
160 len
= snprintf(str
, sizeof(str
), "%d", spl_debug_get_mb());
164 rc
= proc_copyout_string(buffer
, *lenp
, str
+ *ppos
, "\n");
176 proc_dump_kernel(struct ctl_table
*table
, int write
, struct file
*filp
,
177 void __user
*buffer
, size_t *lenp
, loff_t
*ppos
)
192 proc_force_bug(struct ctl_table
*table
, int write
, struct file
*filp
,
193 void __user
*buffer
, size_t *lenp
, loff_t
*ppos
)
198 CERROR("Crashing due to forced SBUG\n");
209 proc_console_max_delay_cs(struct ctl_table
*table
, int write
, struct file
*filp
,
210 void __user
*buffer
, size_t *lenp
, loff_t
*ppos
)
212 int rc
, max_delay_cs
;
213 struct ctl_table dummy
= *table
;
217 dummy
.data
= &max_delay_cs
;
218 dummy
.proc_handler
= &proc_dointvec
;
222 rc
= proc_dointvec(&dummy
, write
, filp
, buffer
, lenp
, ppos
);
226 if (max_delay_cs
<= 0)
229 d
= (max_delay_cs
* HZ
) / 100;
230 if (d
== 0 || d
< spl_console_min_delay
)
233 spl_console_max_delay
= d
;
235 max_delay_cs
= (spl_console_max_delay
* 100) / HZ
;
236 rc
= proc_dointvec(&dummy
, write
, filp
, buffer
, lenp
, ppos
);
243 proc_console_min_delay_cs(struct ctl_table
*table
, int write
, struct file
*filp
,
244 void __user
*buffer
, size_t *lenp
, loff_t
*ppos
)
246 int rc
, min_delay_cs
;
247 struct ctl_table dummy
= *table
;
251 dummy
.data
= &min_delay_cs
;
252 dummy
.proc_handler
= &proc_dointvec
;
256 rc
= proc_dointvec(&dummy
, write
, filp
, buffer
, lenp
, ppos
);
260 if (min_delay_cs
<= 0)
263 d
= (min_delay_cs
* HZ
) / 100;
264 if (d
== 0 || d
> spl_console_max_delay
)
267 spl_console_min_delay
= d
;
269 min_delay_cs
= (spl_console_min_delay
* 100) / HZ
;
270 rc
= proc_dointvec(&dummy
, write
, filp
, buffer
, lenp
, ppos
);
277 proc_console_backoff(struct ctl_table
*table
, int write
, struct file
*filp
,
278 void __user
*buffer
, size_t *lenp
, loff_t
*ppos
)
281 struct ctl_table dummy
= *table
;
284 dummy
.data
= &backoff
;
285 dummy
.proc_handler
= &proc_dointvec
;
289 rc
= proc_dointvec(&dummy
, write
, filp
, buffer
, lenp
, ppos
);
296 spl_console_backoff
= backoff
;
298 backoff
= spl_console_backoff
;
299 rc
= proc_dointvec(&dummy
, write
, filp
, buffer
, lenp
, ppos
);
306 proc_doatomic64(struct ctl_table
*table
, int write
, struct file
*filp
,
307 void __user
*buffer
, size_t *lenp
, loff_t
*ppos
)
310 unsigned long min
= 0, max
= ~0, val
;
311 struct ctl_table dummy
= *table
;
315 dummy
.proc_handler
= &proc_dointvec
;
322 val
= atomic_read((atomic64_t
*)table
->data
);
323 rc
= proc_doulongvec_minmax(&dummy
, write
, filp
,
331 proc_dohostid(struct ctl_table
*table
, int write
, struct file
*filp
,
332 void __user
*buffer
, size_t *lenp
, loff_t
*ppos
)
340 /* We can't use proc_doulongvec_minmax() in the write
341 * case hear because hostid while a hex value has no
342 * leading 0x which confuses the helper function. */
343 rc
= proc_copyin_string(str
, sizeof(str
), buffer
, *lenp
);
347 val
= simple_strtol(str
, &end
, 16);
351 spl_hostid
= (long)val
;
352 sprintf(hw_serial
, "%u", (val
>= 0) ? val
: -val
);
355 len
= snprintf(str
, sizeof(str
), "%lx", spl_hostid
);
359 rc
= proc_copyout_string(buffer
, *lenp
, str
+ *ppos
, "\n");
370 static struct ctl_table spl_table
[] = {
371 /* NB No .strategy entries have been provided since
372 * sysctl(8) prefers to go via /proc for portability.
375 .ctl_name
= CTL_DEBUG_SUBSYS
,
376 .procname
= "debug_subsystem",
377 .data
= &spl_debug_subsys
,
378 .maxlen
= sizeof(unsigned long),
380 .proc_handler
= &proc_dobitmasks
383 .ctl_name
= CTL_DEBUG_MASK
,
384 .procname
= "debug_mask",
385 .data
= &spl_debug_mask
,
386 .maxlen
= sizeof(unsigned long),
388 .proc_handler
= &proc_dobitmasks
391 .ctl_name
= CTL_DEBUG_PRINTK
,
392 .procname
= "debug_printk",
393 .data
= &spl_debug_printk
,
394 .maxlen
= sizeof(unsigned long),
396 .proc_handler
= &proc_dobitmasks
399 .ctl_name
= CTL_DEBUG_MB
,
400 .procname
= "debug_mb",
402 .proc_handler
= &proc_debug_mb
,
405 .ctl_name
= CTL_DEBUG_BINARY
,
406 .procname
= "debug_binary",
407 .data
= &spl_debug_binary
,
408 .maxlen
= sizeof(int),
410 .proc_handler
= &proc_dointvec
,
413 .ctl_name
= CTL_DEBUG_CATASTROPHE
,
414 .procname
= "catastrophe",
415 .data
= &spl_debug_catastrophe
,
416 .maxlen
= sizeof(int),
418 .proc_handler
= &proc_dointvec
,
421 .ctl_name
= CTL_DEBUG_PANIC_ON_BUG
,
422 .procname
= "panic_on_bug",
423 .data
= &spl_debug_panic_on_bug
,
424 .maxlen
= sizeof(int),
426 .proc_handler
= &proc_dointvec
429 .ctl_name
= CTL_DEBUG_PATH
,
430 .procname
= "debug_path",
431 .data
= spl_debug_file_path
,
432 .maxlen
= sizeof(spl_debug_file_path
),
434 .proc_handler
= &proc_dostring
,
437 .ctl_name
= CTL_DEBUG_DUMP
,
438 .procname
= "debug_dump",
440 .proc_handler
= &proc_dump_kernel
,
442 { .ctl_name
= CTL_DEBUG_FORCE_BUG
,
443 .procname
= "force_bug",
445 .proc_handler
= &proc_force_bug
,
448 .ctl_name
= CTL_CONSOLE_RATELIMIT
,
449 .procname
= "console_ratelimit",
450 .data
= &spl_console_ratelimit
,
451 .maxlen
= sizeof(int),
453 .proc_handler
= &proc_dointvec
,
456 .ctl_name
= CTL_CONSOLE_MAX_DELAY_CS
,
457 .procname
= "console_max_delay_centisecs",
458 .maxlen
= sizeof(int),
460 .proc_handler
= &proc_console_max_delay_cs
,
463 .ctl_name
= CTL_CONSOLE_MIN_DELAY_CS
,
464 .procname
= "console_min_delay_centisecs",
465 .maxlen
= sizeof(int),
467 .proc_handler
= &proc_console_min_delay_cs
,
470 .ctl_name
= CTL_CONSOLE_BACKOFF
,
471 .procname
= "console_backoff",
472 .maxlen
= sizeof(int),
474 .proc_handler
= &proc_console_backoff
,
477 .ctl_name
= CTL_STACK_SIZE
,
478 .procname
= "stack_max",
479 .data
= &spl_debug_stack
,
480 .maxlen
= sizeof(int),
482 .proc_handler
= &proc_dointvec
,
486 .ctl_name
= CTL_KMEM_KMEMUSED
,
487 .procname
= "kmem_used",
488 .data
= &kmem_alloc_used
,
489 .maxlen
= sizeof(atomic64_t
),
491 .proc_handler
= &proc_doatomic64
,
494 .ctl_name
= CTL_KMEM_KMEMMAX
,
495 .procname
= "kmem_max",
496 .data
= &kmem_alloc_max
,
497 .maxlen
= sizeof(unsigned long),
498 .extra1
= &table_min
,
499 .extra2
= &table_max
,
501 .proc_handler
= &proc_doulongvec_minmax
,
504 .ctl_name
= CTL_KMEM_VMEMUSED
,
505 .procname
= "vmem_used",
506 .data
= &vmem_alloc_used
,
507 .maxlen
= sizeof(atomic64_t
),
509 .proc_handler
= &proc_doatomic64
,
512 .ctl_name
= CTL_KMEM_VMEMMAX
,
513 .procname
= "vmem_max",
514 .data
= &vmem_alloc_max
,
515 .maxlen
= sizeof(unsigned long),
516 .extra1
= &table_min
,
517 .extra2
= &table_max
,
519 .proc_handler
= &proc_doulongvec_minmax
,
523 .ctl_name
= CTL_HOSTID
,
524 .procname
= "hostid",
526 .maxlen
= sizeof(unsigned long),
528 .proc_handler
= &proc_dohostid
,
531 .ctl_name
= CTL_HW_SERIAL
,
532 .procname
= "hw_serial",
534 .maxlen
= sizeof(hw_serial
),
536 .proc_handler
= &proc_dostring
,
541 static struct ctl_table spl_dir_table
[] = {
557 spl_header
= register_sysctl_table(spl_dir_table
, 0);
558 if (spl_header
== NULL
)
570 ASSERT(spl_header
!= NULL
);
571 unregister_sysctl_table(spl_header
);