sys_info.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. #include <linux/array_size.h>
  3. #include <linux/bitops.h>
  4. #include <linux/cleanup.h>
  5. #include <linux/console.h>
  6. #include <linux/log2.h>
  7. #include <linux/kernel.h>
  8. #include <linux/ftrace.h>
  9. #include <linux/nmi.h>
  10. #include <linux/sched/debug.h>
  11. #include <linux/string.h>
  12. #include <linux/sysctl.h>
  13. #include <linux/sys_info.h>
  14. static const char * const si_names[] = {
  15. [ilog2(SYS_INFO_TASKS)] = "tasks",
  16. [ilog2(SYS_INFO_MEM)] = "mem",
  17. [ilog2(SYS_INFO_TIMERS)] = "timers",
  18. [ilog2(SYS_INFO_LOCKS)] = "locks",
  19. [ilog2(SYS_INFO_FTRACE)] = "ftrace",
  20. [ilog2(SYS_INFO_PANIC_CONSOLE_REPLAY)] = "",
  21. [ilog2(SYS_INFO_ALL_BT)] = "all_bt",
  22. [ilog2(SYS_INFO_BLOCKED_TASKS)] = "blocked_tasks",
  23. };
  24. /*
  25. * Default kernel sys_info mask.
  26. * If a kernel module calls sys_info() with "parameter == 0", then
  27. * this mask will be used.
  28. */
  29. static unsigned long kernel_si_mask;
  30. /* Expecting string like "xxx_sys_info=tasks,mem,timers,locks,ftrace,..." */
  31. unsigned long sys_info_parse_param(char *str)
  32. {
  33. unsigned long si_bits = 0;
  34. char *s, *name;
  35. int i;
  36. s = str;
  37. while ((name = strsep(&s, ",")) && *name) {
  38. i = match_string(si_names, ARRAY_SIZE(si_names), name);
  39. if (i >= 0)
  40. __set_bit(i, &si_bits);
  41. }
  42. return si_bits;
  43. }
  44. #ifdef CONFIG_SYSCTL
  45. static int sys_info_write_handler(const struct ctl_table *table,
  46. void *buffer, size_t *lenp, loff_t *ppos,
  47. unsigned long *si_bits_global)
  48. {
  49. unsigned long si_bits;
  50. int ret;
  51. ret = proc_dostring(table, 1, buffer, lenp, ppos);
  52. if (ret)
  53. return ret;
  54. si_bits = sys_info_parse_param(table->data);
  55. /* The access to the global value is not synchronized. */
  56. WRITE_ONCE(*si_bits_global, si_bits);
  57. return 0;
  58. }
  59. static int sys_info_read_handler(const struct ctl_table *table,
  60. void *buffer, size_t *lenp, loff_t *ppos,
  61. unsigned long *si_bits_global)
  62. {
  63. unsigned long si_bits;
  64. unsigned int len = 0;
  65. char *delim = "";
  66. unsigned int i;
  67. /* The access to the global value is not synchronized. */
  68. si_bits = READ_ONCE(*si_bits_global);
  69. for_each_set_bit(i, &si_bits, ARRAY_SIZE(si_names)) {
  70. if (*si_names[i]) {
  71. len += scnprintf(table->data + len, table->maxlen - len,
  72. "%s%s", delim, si_names[i]);
  73. delim = ",";
  74. }
  75. }
  76. return proc_dostring(table, 0, buffer, lenp, ppos);
  77. }
  78. int sysctl_sys_info_handler(const struct ctl_table *ro_table, int write,
  79. void *buffer, size_t *lenp,
  80. loff_t *ppos)
  81. {
  82. struct ctl_table table;
  83. unsigned int i;
  84. size_t maxlen;
  85. maxlen = 0;
  86. for (i = 0; i < ARRAY_SIZE(si_names); i++)
  87. maxlen += strlen(si_names[i]) + 1;
  88. char *names __free(kfree) = kzalloc(maxlen, GFP_KERNEL);
  89. if (!names)
  90. return -ENOMEM;
  91. table = *ro_table;
  92. table.data = names;
  93. table.maxlen = maxlen;
  94. if (write)
  95. return sys_info_write_handler(&table, buffer, lenp, ppos, ro_table->data);
  96. else
  97. return sys_info_read_handler(&table, buffer, lenp, ppos, ro_table->data);
  98. }
  99. static const struct ctl_table sys_info_sysctls[] = {
  100. {
  101. .procname = "kernel_sys_info",
  102. .data = &kernel_si_mask,
  103. .maxlen = sizeof(kernel_si_mask),
  104. .mode = 0644,
  105. .proc_handler = sysctl_sys_info_handler,
  106. },
  107. };
  108. static int __init sys_info_sysctl_init(void)
  109. {
  110. register_sysctl_init("kernel", sys_info_sysctls);
  111. return 0;
  112. }
  113. subsys_initcall(sys_info_sysctl_init);
  114. #endif
  115. static void __sys_info(unsigned long si_mask)
  116. {
  117. if (si_mask & SYS_INFO_TASKS)
  118. show_state();
  119. if (si_mask & SYS_INFO_MEM)
  120. show_mem();
  121. if (si_mask & SYS_INFO_TIMERS)
  122. sysrq_timer_list_show();
  123. if (si_mask & SYS_INFO_LOCKS)
  124. debug_show_all_locks();
  125. if (si_mask & SYS_INFO_FTRACE)
  126. ftrace_dump(DUMP_ALL);
  127. if (si_mask & SYS_INFO_ALL_BT)
  128. trigger_all_cpu_backtrace();
  129. if (si_mask & SYS_INFO_BLOCKED_TASKS)
  130. show_state_filter(TASK_UNINTERRUPTIBLE);
  131. }
  132. void sys_info(unsigned long si_mask)
  133. {
  134. __sys_info(si_mask ? : kernel_si_mask);
  135. }