summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Zijlstra <peterz@infradead.org>2018-06-07 04:52:03 -0400
committerIngo Molnar <mingo@kernel.org>2018-07-03 03:20:43 -0400
commit9cf57731b63e37ed995b46690adc604891a9a28f (patch)
treec8bba79ceb4c998a5f18222a60747ac52236c5a0
parent4520843dfa34417eb1e2061f60d2345d9ca614e1 (diff)
watchdog/softlockup: Replace "watchdog/%u" threads with cpu_stop_work
Oleg suggested to replace the "watchdog/%u" threads with cpu_stop_work. That removes one thread per CPU while at the same time fixes softlockup vs SCHED_DEADLINE. But more importantly, it does away with the single smpboot_update_cpumask_percpu_thread() user, which allows cleanups/shrinkage of the smpboot interface. Suggested-by: Oleg Nesterov <oleg@redhat.com> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--include/linux/cpuhotplug.h1
-rw-r--r--include/linux/nmi.h5
-rw-r--r--kernel/cpu.c5
-rw-r--r--kernel/watchdog.c137
4 files changed, 71 insertions, 77 deletions
diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h
index 8796ba387152..4cf06a64bc02 100644
--- a/include/linux/cpuhotplug.h
+++ b/include/linux/cpuhotplug.h
@@ -164,6 +164,7 @@ enum cpuhp_state {
164 CPUHP_AP_PERF_POWERPC_NEST_IMC_ONLINE, 164 CPUHP_AP_PERF_POWERPC_NEST_IMC_ONLINE,
165 CPUHP_AP_PERF_POWERPC_CORE_IMC_ONLINE, 165 CPUHP_AP_PERF_POWERPC_CORE_IMC_ONLINE,
166 CPUHP_AP_PERF_POWERPC_THREAD_IMC_ONLINE, 166 CPUHP_AP_PERF_POWERPC_THREAD_IMC_ONLINE,
167 CPUHP_AP_WATCHDOG_ONLINE,
167 CPUHP_AP_WORKQUEUE_ONLINE, 168 CPUHP_AP_WORKQUEUE_ONLINE,
168 CPUHP_AP_RCUTREE_ONLINE, 169 CPUHP_AP_RCUTREE_ONLINE,
169 CPUHP_AP_ONLINE_DYN, 170 CPUHP_AP_ONLINE_DYN,
diff --git a/include/linux/nmi.h b/include/linux/nmi.h
index b8d868d23e79..80664bbeca43 100644
--- a/include/linux/nmi.h
+++ b/include/linux/nmi.h
@@ -33,10 +33,15 @@ extern int sysctl_hardlockup_all_cpu_backtrace;
33#define sysctl_hardlockup_all_cpu_backtrace 0 33#define sysctl_hardlockup_all_cpu_backtrace 0
34#endif /* !CONFIG_SMP */ 34#endif /* !CONFIG_SMP */
35 35
36extern int lockup_detector_online_cpu(unsigned int cpu);
37extern int lockup_detector_offline_cpu(unsigned int cpu);
38
36#else /* CONFIG_LOCKUP_DETECTOR */ 39#else /* CONFIG_LOCKUP_DETECTOR */
37static inline void lockup_detector_init(void) { } 40static inline void lockup_detector_init(void) { }
38static inline void lockup_detector_soft_poweroff(void) { } 41static inline void lockup_detector_soft_poweroff(void) { }
39static inline void lockup_detector_cleanup(void) { } 42static inline void lockup_detector_cleanup(void) { }
43#define lockup_detector_online_cpu NULL
44#define lockup_detector_offline_cpu NULL
40#endif /* !CONFIG_LOCKUP_DETECTOR */ 45#endif /* !CONFIG_LOCKUP_DETECTOR */
41 46
42#ifdef CONFIG_SOFTLOCKUP_DETECTOR 47#ifdef CONFIG_SOFTLOCKUP_DETECTOR
diff --git a/kernel/cpu.c b/kernel/cpu.c
index 0db8938fbb23..191097c45fb1 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -1344,6 +1344,11 @@ static struct cpuhp_step cpuhp_hp_states[] = {
1344 .startup.single = perf_event_init_cpu, 1344 .startup.single = perf_event_init_cpu,
1345 .teardown.single = perf_event_exit_cpu, 1345 .teardown.single = perf_event_exit_cpu,
1346 }, 1346 },
1347 [CPUHP_AP_WATCHDOG_ONLINE] = {
1348 .name = "lockup_detector:online",
1349 .startup.single = lockup_detector_online_cpu,
1350 .teardown.single = lockup_detector_offline_cpu,
1351 },
1347 [CPUHP_AP_WORKQUEUE_ONLINE] = { 1352 [CPUHP_AP_WORKQUEUE_ONLINE] = {
1348 .name = "workqueue:online", 1353 .name = "workqueue:online",
1349 .startup.single = workqueue_online_cpu, 1354 .startup.single = workqueue_online_cpu,
diff --git a/kernel/watchdog.c b/kernel/watchdog.c
index 576d18045811..b81f777838d5 100644
--- a/kernel/watchdog.c
+++ b/kernel/watchdog.c
@@ -18,18 +18,14 @@
18#include <linux/init.h> 18#include <linux/init.h>
19#include <linux/module.h> 19#include <linux/module.h>
20#include <linux/sysctl.h> 20#include <linux/sysctl.h>
21#include <linux/smpboot.h>
22#include <linux/sched/rt.h>
23#include <uapi/linux/sched/types.h>
24#include <linux/tick.h> 21#include <linux/tick.h>
25#include <linux/workqueue.h>
26#include <linux/sched/clock.h> 22#include <linux/sched/clock.h>
27#include <linux/sched/debug.h> 23#include <linux/sched/debug.h>
28#include <linux/sched/isolation.h> 24#include <linux/sched/isolation.h>
25#include <linux/stop_machine.h>
29 26
30#include <asm/irq_regs.h> 27#include <asm/irq_regs.h>
31#include <linux/kvm_para.h> 28#include <linux/kvm_para.h>
32#include <linux/kthread.h>
33 29
34static DEFINE_MUTEX(watchdog_mutex); 30static DEFINE_MUTEX(watchdog_mutex);
35 31
@@ -169,11 +165,10 @@ static void lockup_detector_update_enable(void)
169unsigned int __read_mostly softlockup_panic = 165unsigned int __read_mostly softlockup_panic =
170 CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE; 166 CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE;
171 167
172static bool softlockup_threads_initialized __read_mostly; 168static bool softlockup_initialized __read_mostly;
173static u64 __read_mostly sample_period; 169static u64 __read_mostly sample_period;
174 170
175static DEFINE_PER_CPU(unsigned long, watchdog_touch_ts); 171static DEFINE_PER_CPU(unsigned long, watchdog_touch_ts);
176static DEFINE_PER_CPU(struct task_struct *, softlockup_watchdog);
177static DEFINE_PER_CPU(struct hrtimer, watchdog_hrtimer); 172static DEFINE_PER_CPU(struct hrtimer, watchdog_hrtimer);
178static DEFINE_PER_CPU(bool, softlockup_touch_sync); 173static DEFINE_PER_CPU(bool, softlockup_touch_sync);
179static DEFINE_PER_CPU(bool, soft_watchdog_warn); 174static DEFINE_PER_CPU(bool, soft_watchdog_warn);
@@ -335,6 +330,25 @@ static void watchdog_interrupt_count(void)
335 __this_cpu_inc(hrtimer_interrupts); 330 __this_cpu_inc(hrtimer_interrupts);
336} 331}
337 332
333/*
334 * The watchdog thread function - touches the timestamp.
335 *
336 * It only runs once every sample_period seconds (4 seconds by
337 * default) to reset the softlockup timestamp. If this gets delayed
338 * for more than 2*watchdog_thresh seconds then the debug-printout
339 * triggers in watchdog_timer_fn().
340 */
341static int softlockup_fn(void *data)
342{
343 __this_cpu_write(soft_lockup_hrtimer_cnt,
344 __this_cpu_read(hrtimer_interrupts));
345 __touch_watchdog();
346
347 return 0;
348}
349
350static DEFINE_PER_CPU(struct cpu_stop_work, softlockup_stop_work);
351
338/* watchdog kicker functions */ 352/* watchdog kicker functions */
339static enum hrtimer_restart watchdog_timer_fn(struct hrtimer *hrtimer) 353static enum hrtimer_restart watchdog_timer_fn(struct hrtimer *hrtimer)
340{ 354{
@@ -350,7 +364,9 @@ static enum hrtimer_restart watchdog_timer_fn(struct hrtimer *hrtimer)
350 watchdog_interrupt_count(); 364 watchdog_interrupt_count();
351 365
352 /* kick the softlockup detector */ 366 /* kick the softlockup detector */
353 wake_up_process(__this_cpu_read(softlockup_watchdog)); 367 stop_one_cpu_nowait(smp_processor_id(),
368 softlockup_fn, NULL,
369 this_cpu_ptr(&softlockup_stop_work));
354 370
355 /* .. and repeat */ 371 /* .. and repeat */
356 hrtimer_forward_now(hrtimer, ns_to_ktime(sample_period)); 372 hrtimer_forward_now(hrtimer, ns_to_ktime(sample_period));
@@ -448,17 +464,12 @@ static enum hrtimer_restart watchdog_timer_fn(struct hrtimer *hrtimer)
448 return HRTIMER_RESTART; 464 return HRTIMER_RESTART;
449} 465}
450 466
451static void watchdog_set_prio(unsigned int policy, unsigned int prio)
452{
453 struct sched_param param = { .sched_priority = prio };
454
455 sched_setscheduler(current, policy, &param);
456}
457
458static void watchdog_enable(unsigned int cpu) 467static void watchdog_enable(unsigned int cpu)
459{ 468{
460 struct hrtimer *hrtimer = this_cpu_ptr(&watchdog_hrtimer); 469 struct hrtimer *hrtimer = this_cpu_ptr(&watchdog_hrtimer);
461 470
471 WARN_ON_ONCE(cpu != smp_processor_id());
472
462 /* 473 /*
463 * Start the timer first to prevent the NMI watchdog triggering 474 * Start the timer first to prevent the NMI watchdog triggering
464 * before the timer has a chance to fire. 475 * before the timer has a chance to fire.
@@ -473,15 +484,14 @@ static void watchdog_enable(unsigned int cpu)
473 /* Enable the perf event */ 484 /* Enable the perf event */
474 if (watchdog_enabled & NMI_WATCHDOG_ENABLED) 485 if (watchdog_enabled & NMI_WATCHDOG_ENABLED)
475 watchdog_nmi_enable(cpu); 486 watchdog_nmi_enable(cpu);
476
477 watchdog_set_prio(SCHED_FIFO, MAX_RT_PRIO - 1);
478} 487}
479 488
480static void watchdog_disable(unsigned int cpu) 489static void watchdog_disable(unsigned int cpu)
481{ 490{
482 struct hrtimer *hrtimer = this_cpu_ptr(&watchdog_hrtimer); 491 struct hrtimer *hrtimer = this_cpu_ptr(&watchdog_hrtimer);
483 492
484 watchdog_set_prio(SCHED_NORMAL, 0); 493 WARN_ON_ONCE(cpu != smp_processor_id());
494
485 /* 495 /*
486 * Disable the perf event first. That prevents that a large delay 496 * Disable the perf event first. That prevents that a large delay
487 * between disabling the timer and disabling the perf event causes 497 * between disabling the timer and disabling the perf event causes
@@ -491,77 +501,63 @@ static void watchdog_disable(unsigned int cpu)
491 hrtimer_cancel(hrtimer); 501 hrtimer_cancel(hrtimer);
492} 502}
493 503
494static void watchdog_cleanup(unsigned int cpu, bool online) 504static int softlockup_stop_fn(void *data)
495{ 505{
496 watchdog_disable(cpu); 506 watchdog_disable(smp_processor_id());
507 return 0;
497} 508}
498 509
499static int watchdog_should_run(unsigned int cpu) 510static void softlockup_stop_all(void)
500{ 511{
501 return __this_cpu_read(hrtimer_interrupts) != 512 int cpu;
502 __this_cpu_read(soft_lockup_hrtimer_cnt); 513
514 if (!softlockup_initialized)
515 return;
516
517 for_each_cpu(cpu, &watchdog_allowed_mask)
518 smp_call_on_cpu(cpu, softlockup_stop_fn, NULL, false);
519
520 cpumask_clear(&watchdog_allowed_mask);
503} 521}
504 522
505/* 523static int softlockup_start_fn(void *data)
506 * The watchdog thread function - touches the timestamp.
507 *
508 * It only runs once every sample_period seconds (4 seconds by
509 * default) to reset the softlockup timestamp. If this gets delayed
510 * for more than 2*watchdog_thresh seconds then the debug-printout
511 * triggers in watchdog_timer_fn().
512 */
513static void watchdog(unsigned int cpu)
514{ 524{
515 __this_cpu_write(soft_lockup_hrtimer_cnt, 525 watchdog_enable(smp_processor_id());
516 __this_cpu_read(hrtimer_interrupts)); 526 return 0;
517 __touch_watchdog();
518} 527}
519 528
520static struct smp_hotplug_thread watchdog_threads = { 529static void softlockup_start_all(void)
521 .store = &softlockup_watchdog,
522 .thread_should_run = watchdog_should_run,
523 .thread_fn = watchdog,
524 .thread_comm = "watchdog/%u",
525 .setup = watchdog_enable,
526 .cleanup = watchdog_cleanup,
527 .park = watchdog_disable,
528 .unpark = watchdog_enable,
529};
530
531static void softlockup_update_smpboot_threads(void)
532{ 530{
533 lockdep_assert_held(&watchdog_mutex); 531 int cpu;
534
535 if (!softlockup_threads_initialized)
536 return;
537 532
538 smpboot_update_cpumask_percpu_thread(&watchdog_threads, 533 cpumask_copy(&watchdog_allowed_mask, &watchdog_cpumask);
539 &watchdog_allowed_mask); 534 for_each_cpu(cpu, &watchdog_allowed_mask)
535 smp_call_on_cpu(cpu, softlockup_start_fn, NULL, false);
540} 536}
541 537
542/* Temporarily park all watchdog threads */ 538int lockup_detector_online_cpu(unsigned int cpu)
543static void softlockup_park_all_threads(void)
544{ 539{
545 cpumask_clear(&watchdog_allowed_mask); 540 watchdog_enable(cpu);
546 softlockup_update_smpboot_threads(); 541 return 0;
547} 542}
548 543
549/* Unpark enabled threads */ 544int lockup_detector_offline_cpu(unsigned int cpu)
550static void softlockup_unpark_threads(void)
551{ 545{
552 cpumask_copy(&watchdog_allowed_mask, &watchdog_cpumask); 546 watchdog_disable(cpu);
553 softlockup_update_smpboot_threads(); 547 return 0;
554} 548}
555 549
556static void lockup_detector_reconfigure(void) 550static void lockup_detector_reconfigure(void)
557{ 551{
558 cpus_read_lock(); 552 cpus_read_lock();
559 watchdog_nmi_stop(); 553 watchdog_nmi_stop();
560 softlockup_park_all_threads(); 554
555 softlockup_stop_all();
561 set_sample_period(); 556 set_sample_period();
562 lockup_detector_update_enable(); 557 lockup_detector_update_enable();
563 if (watchdog_enabled && watchdog_thresh) 558 if (watchdog_enabled && watchdog_thresh)
564 softlockup_unpark_threads(); 559 softlockup_start_all();
560
565 watchdog_nmi_start(); 561 watchdog_nmi_start();
566 cpus_read_unlock(); 562 cpus_read_unlock();
567 /* 563 /*
@@ -580,8 +576,6 @@ static void lockup_detector_reconfigure(void)
580 */ 576 */
581static __init void lockup_detector_setup(void) 577static __init void lockup_detector_setup(void)
582{ 578{
583 int ret;
584
585 /* 579 /*
586 * If sysctl is off and watchdog got disabled on the command line, 580 * If sysctl is off and watchdog got disabled on the command line,
587 * nothing to do here. 581 * nothing to do here.
@@ -592,24 +586,13 @@ static __init void lockup_detector_setup(void)
592 !(watchdog_enabled && watchdog_thresh)) 586 !(watchdog_enabled && watchdog_thresh))
593 return; 587 return;
594 588
595 ret = smpboot_register_percpu_thread_cpumask(&watchdog_threads,
596 &watchdog_allowed_mask);
597 if (ret) {
598 pr_err("Failed to initialize soft lockup detector threads\n");
599 return;
600 }
601
602 mutex_lock(&watchdog_mutex); 589 mutex_lock(&watchdog_mutex);
603 softlockup_threads_initialized = true;
604 lockup_detector_reconfigure(); 590 lockup_detector_reconfigure();
591 softlockup_initialized = true;
605 mutex_unlock(&watchdog_mutex); 592 mutex_unlock(&watchdog_mutex);
606} 593}
607 594
608#else /* CONFIG_SOFTLOCKUP_DETECTOR */ 595#else /* CONFIG_SOFTLOCKUP_DETECTOR */
609static inline int watchdog_park_threads(void) { return 0; }
610static inline void watchdog_unpark_threads(void) { }
611static inline int watchdog_enable_all_cpus(void) { return 0; }
612static inline void watchdog_disable_all_cpus(void) { }
613static void lockup_detector_reconfigure(void) 596static void lockup_detector_reconfigure(void)
614{ 597{
615 cpus_read_lock(); 598 cpus_read_lock();