| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166 |
- // SPDX-License-Identifier: GPL-2.0-only
- #include <linux/array_size.h>
- #include <linux/bitops.h>
- #include <linux/cleanup.h>
- #include <linux/console.h>
- #include <linux/log2.h>
- #include <linux/kernel.h>
- #include <linux/ftrace.h>
- #include <linux/nmi.h>
- #include <linux/sched/debug.h>
- #include <linux/string.h>
- #include <linux/sysctl.h>
- #include <linux/sys_info.h>
- static const char * const si_names[] = {
- [ilog2(SYS_INFO_TASKS)] = "tasks",
- [ilog2(SYS_INFO_MEM)] = "mem",
- [ilog2(SYS_INFO_TIMERS)] = "timers",
- [ilog2(SYS_INFO_LOCKS)] = "locks",
- [ilog2(SYS_INFO_FTRACE)] = "ftrace",
- [ilog2(SYS_INFO_PANIC_CONSOLE_REPLAY)] = "",
- [ilog2(SYS_INFO_ALL_BT)] = "all_bt",
- [ilog2(SYS_INFO_BLOCKED_TASKS)] = "blocked_tasks",
- };
- /*
- * Default kernel sys_info mask.
- * If a kernel module calls sys_info() with "parameter == 0", then
- * this mask will be used.
- */
- static unsigned long kernel_si_mask;
- /* Expecting string like "xxx_sys_info=tasks,mem,timers,locks,ftrace,..." */
- unsigned long sys_info_parse_param(char *str)
- {
- unsigned long si_bits = 0;
- char *s, *name;
- int i;
- s = str;
- while ((name = strsep(&s, ",")) && *name) {
- i = match_string(si_names, ARRAY_SIZE(si_names), name);
- if (i >= 0)
- __set_bit(i, &si_bits);
- }
- return si_bits;
- }
- #ifdef CONFIG_SYSCTL
- static int sys_info_write_handler(const struct ctl_table *table,
- void *buffer, size_t *lenp, loff_t *ppos,
- unsigned long *si_bits_global)
- {
- unsigned long si_bits;
- int ret;
- ret = proc_dostring(table, 1, buffer, lenp, ppos);
- if (ret)
- return ret;
- si_bits = sys_info_parse_param(table->data);
- /* The access to the global value is not synchronized. */
- WRITE_ONCE(*si_bits_global, si_bits);
- return 0;
- }
- static int sys_info_read_handler(const struct ctl_table *table,
- void *buffer, size_t *lenp, loff_t *ppos,
- unsigned long *si_bits_global)
- {
- unsigned long si_bits;
- unsigned int len = 0;
- char *delim = "";
- unsigned int i;
- /* The access to the global value is not synchronized. */
- si_bits = READ_ONCE(*si_bits_global);
- for_each_set_bit(i, &si_bits, ARRAY_SIZE(si_names)) {
- if (*si_names[i]) {
- len += scnprintf(table->data + len, table->maxlen - len,
- "%s%s", delim, si_names[i]);
- delim = ",";
- }
- }
- return proc_dostring(table, 0, buffer, lenp, ppos);
- }
- int sysctl_sys_info_handler(const struct ctl_table *ro_table, int write,
- void *buffer, size_t *lenp,
- loff_t *ppos)
- {
- struct ctl_table table;
- unsigned int i;
- size_t maxlen;
- maxlen = 0;
- for (i = 0; i < ARRAY_SIZE(si_names); i++)
- maxlen += strlen(si_names[i]) + 1;
- char *names __free(kfree) = kzalloc(maxlen, GFP_KERNEL);
- if (!names)
- return -ENOMEM;
- table = *ro_table;
- table.data = names;
- table.maxlen = maxlen;
- if (write)
- return sys_info_write_handler(&table, buffer, lenp, ppos, ro_table->data);
- else
- return sys_info_read_handler(&table, buffer, lenp, ppos, ro_table->data);
- }
- static const struct ctl_table sys_info_sysctls[] = {
- {
- .procname = "kernel_sys_info",
- .data = &kernel_si_mask,
- .maxlen = sizeof(kernel_si_mask),
- .mode = 0644,
- .proc_handler = sysctl_sys_info_handler,
- },
- };
- static int __init sys_info_sysctl_init(void)
- {
- register_sysctl_init("kernel", sys_info_sysctls);
- return 0;
- }
- subsys_initcall(sys_info_sysctl_init);
- #endif
- static void __sys_info(unsigned long si_mask)
- {
- if (si_mask & SYS_INFO_TASKS)
- show_state();
- if (si_mask & SYS_INFO_MEM)
- show_mem();
- if (si_mask & SYS_INFO_TIMERS)
- sysrq_timer_list_show();
- if (si_mask & SYS_INFO_LOCKS)
- debug_show_all_locks();
- if (si_mask & SYS_INFO_FTRACE)
- ftrace_dump(DUMP_ALL);
- if (si_mask & SYS_INFO_ALL_BT)
- trigger_all_cpu_backtrace();
- if (si_mask & SYS_INFO_BLOCKED_TASKS)
- show_state_filter(TASK_UNINTERRUPTIBLE);
- }
- void sys_info(unsigned long si_mask)
- {
- __sys_info(si_mask ? : kernel_si_mask);
- }
|