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
 ==================
 
 
 #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.
 #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 */
 
 #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)