2
0
mirror of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git synced 2025-09-04 20:19:47 +08:00

panic: add 'panic_sys_info' sysctl to take human readable string parameter

Bitmap definition for 'panic_print' is hard to remember and decode.  Add
'panic_sys_info='sysctl to take human readable string like
"tasks,mem,timers,locks,ftrace,..." and translate it into bitmap.

The detailed mapping is:
	SYS_INFO_TASKS		"tasks"
	SYS_INFO_MEM		"mem"
	SYS_INFO_TIMERS		"timers"
	SYS_INFO_LOCKS		"locks"
	SYS_INFO_FTRACE		"ftrace"
	SYS_INFO_ALL_CPU_BT	"all_bt"
	SYS_INFO_BLOCKED_TASKS	"blocked_tasks"

[nathan@kernel.org: add __maybe_unused to sys_info_avail]
  Link: https://lkml.kernel.org/r/20250708-fix-clang-sys_info_avail-warning-v1-1-60d239eacd64@kernel.org
Link: https://lkml.kernel.org/r/20250703021004.42328-4-feng.tang@linux.alibaba.com
Signed-off-by: Feng Tang <feng.tang@linux.alibaba.com>
Suggested-by: Petr Mladek <pmladek@suse.com>
Cc: John Ogness <john.ogness@linutronix.de>
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: Lance Yang <lance.yang@linux.dev>
Cc: "Paul E . McKenney" <paulmck@kernel.org>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Nathan Chancellor <nathan@kernel.org>
Cc: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
This commit is contained in:
Feng Tang 2025-07-03 10:10:02 +08:00 committed by Andrew Morton
parent b76e89e50f
commit d747755917
4 changed files with 123 additions and 0 deletions

View File

@ -899,6 +899,24 @@ So for example to print tasks and memory info on panic, user can::
echo 3 > /proc/sys/kernel/panic_print
panic_sys_info
==============
A comma separated list of extra information to be dumped on panic,
for example, "tasks,mem,timers,...". It is a human readable alternative
to 'panic_print'. Possible values are:
============= ===================================================
tasks print all tasks info
mem print system memory info
timer print timers info
lock print locks info if CONFIG_LOCKDEP is on
ftrace print ftrace buffer
all_bt print all CPUs backtrace (if available in the arch)
blocked_tasks print only tasks in uninterruptible (blocked) state
============= ===================================================
panic_on_rcu_stall
==================

View File

@ -2,6 +2,8 @@
#ifndef _LINUX_SYS_INFO_H
#define _LINUX_SYS_INFO_H
#include <linux/sysctl.h>
/*
* SYS_INFO_PANIC_CONSOLE_REPLAY is for panic case only, as it needs special
* handling which only fits panic case.
@ -16,5 +18,11 @@
#define SYS_INFO_BLOCKED_TASKS 0x00000080
void sys_info(unsigned long si_mask);
unsigned long sys_info_parse_param(char *str);
#ifdef CONFIG_SYSCTL
int sysctl_sys_info_handler(const struct ctl_table *ro_table, int write,
void *buffer, size_t *lenp,
loff_t *ppos);
#endif
#endif /* _LINUX_SYS_INFO_H */

View File

@ -126,6 +126,13 @@ static const struct ctl_table kern_panic_table[] = {
.mode = 0644,
.proc_handler = proc_douintvec,
},
{
.procname = "panic_sys_info",
.data = &panic_print,
.maxlen = sizeof(panic_print),
.mode = 0644,
.proc_handler = sysctl_sys_info_handler,
},
};
static __init int kernel_panic_sysctls_init(void)

View File

@ -3,10 +3,100 @@
#include <linux/console.h>
#include <linux/kernel.h>
#include <linux/ftrace.h>
#include <linux/sysctl.h>
#include <linux/nmi.h>
#include <linux/sys_info.h>
struct sys_info_name {
unsigned long bit;
const char *name;
};
/*
* When 'si_names' gets updated, please make sure the 'sys_info_avail'
* below is updated accordingly.
*/
static const struct sys_info_name si_names[] = {
{ SYS_INFO_TASKS, "tasks" },
{ SYS_INFO_MEM, "mem" },
{ SYS_INFO_TIMERS, "timers" },
{ SYS_INFO_LOCKS, "locks" },
{ SYS_INFO_FTRACE, "ftrace" },
{ SYS_INFO_ALL_CPU_BT, "all_bt" },
{ SYS_INFO_BLOCKED_TASKS, "blocked_tasks" },
};
/* 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) {
for (i = 0; i < ARRAY_SIZE(si_names); i++) {
if (!strcmp(name, si_names[i].name)) {
si_bits |= si_names[i].bit;
break;
}
}
}
return si_bits;
}
#ifdef CONFIG_SYSCTL
static const char sys_info_avail[] __maybe_unused = "tasks,mem,timers,locks,ftrace,all_bt,blocked_tasks";
int sysctl_sys_info_handler(const struct ctl_table *ro_table, int write,
void *buffer, size_t *lenp,
loff_t *ppos)
{
char names[sizeof(sys_info_avail) + 1];
struct ctl_table table;
unsigned long *si_bits_global;
si_bits_global = ro_table->data;
if (write) {
unsigned long si_bits;
int ret;
table = *ro_table;
table.data = names;
table.maxlen = sizeof(names);
ret = proc_dostring(&table, write, buffer, lenp, ppos);
if (ret)
return ret;
si_bits = sys_info_parse_param(names);
/* The access to the global value is not synchronized. */
WRITE_ONCE(*si_bits_global, si_bits);
return 0;
} else {
/* for 'read' operation */
char *delim = "";
int i, len = 0;
for (i = 0; i < ARRAY_SIZE(si_names); i++) {
if (*si_bits_global & si_names[i].bit) {
len += scnprintf(names + len, sizeof(names) - len,
"%s%s", delim, si_names[i].name);
delim = ",";
}
}
table = *ro_table;
table.data = names;
table.maxlen = sizeof(names);
return proc_dostring(&table, write, buffer, lenp, ppos);
}
}
#endif
void sys_info(unsigned long si_mask)
{
if (si_mask & SYS_INFO_TASKS)