aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2017-09-12 15:37:18 -0400
committerIngo Molnar <mingo@kernel.org>2017-09-14 05:41:08 -0400
commit178b9f7a36d2c74a38274b66dd89f53611298a19 (patch)
tree6ea60b3626a552baa282502b62cd19b4429889bf
parent091549858ed881e5f3054374af4f5b1cac681d50 (diff)
watchdog/hardlockup/perf: Implement init time perf validation
The watchdog tries to create perf events even after it figured out that perf is not functional or the requested event is not supported. That's braindead as this can be done once at init time and if not supported the NMI watchdog can be turned off unconditonally. Implement the perf hardlockup detector functionality for that. This creates a new event create function, which will replace the unholy mess of the existing one in later patches. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Reviewed-by: Don Zickus <dzickus@redhat.com> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Borislav Petkov <bp@alien8.de> Cc: Chris Metcalf <cmetcalf@mellanox.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Nicholas Piggin <npiggin@gmail.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Sebastian Siewior <bigeasy@linutronix.de> Cc: Ulrich Obergfell <uobergfe@redhat.com> Link: http://lkml.kernel.org/r/20170912194148.019090547@linutronix.de Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--include/linux/nmi.h8
-rw-r--r--kernel/watchdog_hld.c37
2 files changed, 43 insertions, 2 deletions
diff --git a/include/linux/nmi.h b/include/linux/nmi.h
index eee255bc0fd6..72c62a809e92 100644
--- a/include/linux/nmi.h
+++ b/include/linux/nmi.h
@@ -93,14 +93,18 @@ extern void hardlockup_detector_perf_stop(void);
93extern void hardlockup_detector_perf_restart(void); 93extern void hardlockup_detector_perf_restart(void);
94extern void hardlockup_detector_perf_disable(void); 94extern void hardlockup_detector_perf_disable(void);
95extern void hardlockup_detector_perf_cleanup(void); 95extern void hardlockup_detector_perf_cleanup(void);
96extern int hardlockup_detector_perf_init(void);
96#else 97#else
97static inline void hardlockup_detector_perf_stop(void) { } 98static inline void hardlockup_detector_perf_stop(void) { }
98static inline void hardlockup_detector_perf_restart(void) { } 99static inline void hardlockup_detector_perf_restart(void) { }
99static inline void hardlockup_detector_perf_disable(void) { } 100static inline void hardlockup_detector_perf_disable(void) { }
100static inline void hardlockup_detector_perf_cleanup(void) { } 101static inline void hardlockup_detector_perf_cleanup(void) { }
101#if !defined(CONFIG_HAVE_NMI_WATCHDOG) 102# if !defined(CONFIG_HAVE_NMI_WATCHDOG)
103static inline int hardlockup_detector_perf_init(void) { return -ENODEV; }
102static inline void arch_touch_nmi_watchdog(void) {} 104static inline void arch_touch_nmi_watchdog(void) {}
103#endif 105# else
106static inline int hardlockup_detector_perf_init(void) { return 0; }
107# endif
104#endif 108#endif
105 109
106void watchdog_nmi_reconfigure(bool run); 110void watchdog_nmi_reconfigure(bool run);
diff --git a/kernel/watchdog_hld.c b/kernel/watchdog_hld.c
index 0aa191ee3d51..f7e752e6e9b4 100644
--- a/kernel/watchdog_hld.c
+++ b/kernel/watchdog_hld.c
@@ -238,6 +238,27 @@ out:
238 return 0; 238 return 0;
239} 239}
240 240
241static int hardlockup_detector_event_create(void)
242{
243 unsigned int cpu = smp_processor_id();
244 struct perf_event_attr *wd_attr;
245 struct perf_event *evt;
246
247 wd_attr = &wd_hw_attr;
248 wd_attr->sample_period = hw_nmi_get_sample_period(watchdog_thresh);
249
250 /* Try to register using hardware perf events */
251 evt = perf_event_create_kernel_counter(wd_attr, cpu, NULL,
252 watchdog_overflow_callback, NULL);
253 if (IS_ERR(evt)) {
254 pr_info("Perf event create on CPU %d failed with %ld\n", cpu,
255 PTR_ERR(evt));
256 return PTR_ERR(evt);
257 }
258 this_cpu_write(watchdog_ev, evt);
259 return 0;
260}
261
241/** 262/**
242 * hardlockup_detector_perf_disable - Disable the local event 263 * hardlockup_detector_perf_disable - Disable the local event
243 */ 264 */
@@ -315,3 +336,19 @@ void __init hardlockup_detector_perf_restart(void)
315 perf_event_enable(event); 336 perf_event_enable(event);
316 } 337 }
317} 338}
339
340/**
341 * hardlockup_detector_perf_init - Probe whether NMI event is available at all
342 */
343int __init hardlockup_detector_perf_init(void)
344{
345 int ret = hardlockup_detector_event_create();
346
347 if (ret) {
348 pr_info("Perf NMI watchdog permanetely disabled\n");
349 } else {
350 perf_event_release_kernel(this_cpu_read(watchdog_ev));
351 this_cpu_write(watchdog_ev, NULL);
352 }
353 return ret;
354}