nmi_watchdog.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. /*
  2. * Detect Hard Lockups using the NMI
  3. *
  4. * started by Don Zickus, Copyright (C) 2010 Red Hat, Inc.
  5. *
  6. * this code detects hard lockups: incidents in where on a CPU
  7. * the kernel does not respond to anything except NMI.
  8. *
  9. * Note: Most of this code is borrowed heavily from softlockup.c,
  10. * so thanks to Ingo for the initial implementation.
  11. * Some chunks also taken from arch/x86/kernel/apic/nmi.c, thanks
  12. * to those contributors as well.
  13. */
  14. #include <linux/mm.h>
  15. #include <linux/cpu.h>
  16. #include <linux/nmi.h>
  17. #include <linux/init.h>
  18. #include <linux/delay.h>
  19. #include <linux/freezer.h>
  20. #include <linux/lockdep.h>
  21. #include <linux/notifier.h>
  22. #include <linux/module.h>
  23. #include <linux/sysctl.h>
  24. #include <asm/irq_regs.h>
  25. #include <linux/perf_event.h>
  26. static DEFINE_PER_CPU(struct perf_event *, nmi_watchdog_ev);
  27. static DEFINE_PER_CPU(int, nmi_watchdog_touch);
  28. static DEFINE_PER_CPU(long, alert_counter);
  29. static int panic_on_timeout;
  30. void touch_nmi_watchdog(void)
  31. {
  32. __raw_get_cpu_var(nmi_watchdog_touch) = 1;
  33. touch_softlockup_watchdog();
  34. }
  35. EXPORT_SYMBOL(touch_nmi_watchdog);
  36. void touch_all_nmi_watchdog(void)
  37. {
  38. int cpu;
  39. for_each_online_cpu(cpu)
  40. per_cpu(nmi_watchdog_touch, cpu) = 1;
  41. touch_softlockup_watchdog();
  42. }
  43. static int __init setup_nmi_watchdog(char *str)
  44. {
  45. if (!strncmp(str, "panic", 5)) {
  46. panic_on_timeout = 1;
  47. str = strchr(str, ',');
  48. if (!str)
  49. return 1;
  50. ++str;
  51. }
  52. return 1;
  53. }
  54. __setup("nmi_watchdog=", setup_nmi_watchdog);
  55. struct perf_event_attr wd_hw_attr = {
  56. .type = PERF_TYPE_HARDWARE,
  57. .config = PERF_COUNT_HW_CPU_CYCLES,
  58. .size = sizeof(struct perf_event_attr),
  59. .pinned = 1,
  60. .disabled = 1,
  61. };
  62. struct perf_event_attr wd_sw_attr = {
  63. .type = PERF_TYPE_SOFTWARE,
  64. .config = PERF_COUNT_SW_CPU_CLOCK,
  65. .size = sizeof(struct perf_event_attr),
  66. .pinned = 1,
  67. .disabled = 1,
  68. };
  69. void wd_overflow(struct perf_event *event, int nmi,
  70. struct perf_sample_data *data,
  71. struct pt_regs *regs)
  72. {
  73. int cpu = smp_processor_id();
  74. int touched = 0;
  75. if (__get_cpu_var(nmi_watchdog_touch)) {
  76. per_cpu(nmi_watchdog_touch, cpu) = 0;
  77. touched = 1;
  78. }
  79. /* check to see if the cpu is doing anything */
  80. if (!touched && hw_nmi_is_cpu_stuck(regs)) {
  81. /*
  82. * Ayiee, looks like this CPU is stuck ...
  83. * wait a few IRQs (5 seconds) before doing the oops ...
  84. */
  85. per_cpu(alert_counter, cpu) += 1;
  86. if (per_cpu(alert_counter, cpu) == 5) {
  87. if (panic_on_timeout)
  88. panic("NMI Watchdog detected LOCKUP on cpu %d", cpu);
  89. else
  90. WARN(1, "NMI Watchdog detected LOCKUP on cpu %d", cpu);
  91. }
  92. } else {
  93. per_cpu(alert_counter, cpu) = 0;
  94. }
  95. return;
  96. }
  97. static int enable_nmi_watchdog(int cpu)
  98. {
  99. struct perf_event *event;
  100. struct perf_event_attr *wd_attr;
  101. event = per_cpu(nmi_watchdog_ev, cpu);
  102. if (event && event->state > PERF_EVENT_STATE_OFF)
  103. return 0;
  104. if (event == NULL) {
  105. /* Try to register using hardware perf events first */
  106. wd_attr = &wd_hw_attr;
  107. wd_attr->sample_period = hw_nmi_get_sample_period();
  108. event = perf_event_create_kernel_counter(wd_attr, cpu, -1, wd_overflow);
  109. if (IS_ERR(event)) {
  110. /* hardware doesn't exist or not supported, fallback to software events */
  111. printk(KERN_INFO "nmi_watchdog: hardware not available, trying software events\n");
  112. wd_attr = &wd_sw_attr;
  113. wd_attr->sample_period = NSEC_PER_SEC;
  114. event = perf_event_create_kernel_counter(wd_attr, cpu, -1, wd_overflow);
  115. if (IS_ERR(event)) {
  116. printk(KERN_ERR "nmi watchdog failed to create perf event on %i: %p\n", cpu, event);
  117. return -1;
  118. }
  119. }
  120. per_cpu(nmi_watchdog_ev, cpu) = event;
  121. }
  122. perf_event_enable(per_cpu(nmi_watchdog_ev, cpu));
  123. return 0;
  124. }
  125. static void disable_nmi_watchdog(int cpu)
  126. {
  127. struct perf_event *event;
  128. event = per_cpu(nmi_watchdog_ev, cpu);
  129. if (event) {
  130. perf_event_disable(per_cpu(nmi_watchdog_ev, cpu));
  131. per_cpu(nmi_watchdog_ev, cpu) = NULL;
  132. perf_event_release_kernel(event);
  133. }
  134. }
  135. #ifdef CONFIG_SYSCTL
  136. /*
  137. * proc handler for /proc/sys/kernel/nmi_watchdog
  138. */
  139. int nmi_watchdog_enabled;
  140. int proc_nmi_enabled(struct ctl_table *table, int write,
  141. void __user *buffer, size_t *length, loff_t *ppos)
  142. {
  143. int cpu;
  144. if (!write) {
  145. struct perf_event *event;
  146. for_each_online_cpu(cpu) {
  147. event = per_cpu(nmi_watchdog_ev, cpu);
  148. if (event && event->state > PERF_EVENT_STATE_OFF) {
  149. nmi_watchdog_enabled = 1;
  150. break;
  151. }
  152. }
  153. proc_dointvec(table, write, buffer, length, ppos);
  154. return 0;
  155. }
  156. touch_all_nmi_watchdog();
  157. proc_dointvec(table, write, buffer, length, ppos);
  158. if (nmi_watchdog_enabled) {
  159. for_each_online_cpu(cpu)
  160. if (enable_nmi_watchdog(cpu)) {
  161. printk(KERN_ERR "NMI watchdog failed configuration, "
  162. " can not be enabled\n");
  163. }
  164. } else {
  165. for_each_online_cpu(cpu)
  166. disable_nmi_watchdog(cpu);
  167. }
  168. return 0;
  169. }
  170. #endif /* CONFIG_SYSCTL */
  171. /*
  172. * Create/destroy watchdog threads as CPUs come and go:
  173. */
  174. static int __cpuinit
  175. cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
  176. {
  177. int hotcpu = (unsigned long)hcpu;
  178. switch (action) {
  179. case CPU_UP_PREPARE:
  180. case CPU_UP_PREPARE_FROZEN:
  181. per_cpu(nmi_watchdog_touch, hotcpu) = 0;
  182. break;
  183. case CPU_ONLINE:
  184. case CPU_ONLINE_FROZEN:
  185. if (enable_nmi_watchdog(hotcpu))
  186. return NOTIFY_BAD;
  187. break;
  188. #ifdef CONFIG_HOTPLUG_CPU
  189. case CPU_UP_CANCELED:
  190. case CPU_UP_CANCELED_FROZEN:
  191. disable_nmi_watchdog(hotcpu);
  192. case CPU_DEAD:
  193. case CPU_DEAD_FROZEN:
  194. break;
  195. #endif /* CONFIG_HOTPLUG_CPU */
  196. }
  197. return NOTIFY_OK;
  198. }
  199. static struct notifier_block __cpuinitdata cpu_nfb = {
  200. .notifier_call = cpu_callback
  201. };
  202. static int __initdata nonmi_watchdog;
  203. static int __init nonmi_watchdog_setup(char *str)
  204. {
  205. nonmi_watchdog = 1;
  206. return 1;
  207. }
  208. __setup("nonmi_watchdog", nonmi_watchdog_setup);
  209. static int __init spawn_nmi_watchdog_task(void)
  210. {
  211. void *cpu = (void *)(long)smp_processor_id();
  212. int err;
  213. if (nonmi_watchdog)
  214. return 0;
  215. err = cpu_callback(&cpu_nfb, CPU_UP_PREPARE, cpu);
  216. if (err == NOTIFY_BAD) {
  217. BUG();
  218. return 1;
  219. }
  220. cpu_callback(&cpu_nfb, CPU_ONLINE, cpu);
  221. register_cpu_notifier(&cpu_nfb);
  222. return 0;
  223. }
  224. early_initcall(spawn_nmi_watchdog_task);