aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/watchdog.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/watchdog.c')
-rw-r--r--kernel/watchdog.c65
1 files changed, 32 insertions, 33 deletions
diff --git a/kernel/watchdog.c b/kernel/watchdog.c
index 613bc1f04610..6e3c41a4024c 100644
--- a/kernel/watchdog.c
+++ b/kernel/watchdog.c
@@ -43,8 +43,7 @@ static DEFINE_PER_CPU(unsigned long, hrtimer_interrupts_saved);
43static DEFINE_PER_CPU(struct perf_event *, watchdog_ev); 43static DEFINE_PER_CPU(struct perf_event *, watchdog_ev);
44#endif 44#endif
45 45
46static int __read_mostly did_panic; 46static int no_watchdog;
47static int __initdata no_watchdog;
48 47
49 48
50/* boot commands */ 49/* boot commands */
@@ -122,7 +121,7 @@ static void __touch_watchdog(void)
122 121
123void touch_softlockup_watchdog(void) 122void touch_softlockup_watchdog(void)
124{ 123{
125 __get_cpu_var(watchdog_touch_ts) = 0; 124 __raw_get_cpu_var(watchdog_touch_ts) = 0;
126} 125}
127EXPORT_SYMBOL(touch_softlockup_watchdog); 126EXPORT_SYMBOL(touch_softlockup_watchdog);
128 127
@@ -142,7 +141,14 @@ void touch_all_softlockup_watchdogs(void)
142#ifdef CONFIG_HARDLOCKUP_DETECTOR 141#ifdef CONFIG_HARDLOCKUP_DETECTOR
143void touch_nmi_watchdog(void) 142void touch_nmi_watchdog(void)
144{ 143{
145 __get_cpu_var(watchdog_nmi_touch) = true; 144 if (watchdog_enabled) {
145 unsigned cpu;
146
147 for_each_present_cpu(cpu) {
148 if (per_cpu(watchdog_nmi_touch, cpu) != true)
149 per_cpu(watchdog_nmi_touch, cpu) = true;
150 }
151 }
146 touch_softlockup_watchdog(); 152 touch_softlockup_watchdog();
147} 153}
148EXPORT_SYMBOL(touch_nmi_watchdog); 154EXPORT_SYMBOL(touch_nmi_watchdog);
@@ -180,18 +186,6 @@ static int is_softlockup(unsigned long touch_ts)
180 return 0; 186 return 0;
181} 187}
182 188
183static int
184watchdog_panic(struct notifier_block *this, unsigned long event, void *ptr)
185{
186 did_panic = 1;
187
188 return NOTIFY_DONE;
189}
190
191static struct notifier_block panic_block = {
192 .notifier_call = watchdog_panic,
193};
194
195#ifdef CONFIG_HARDLOCKUP_DETECTOR 189#ifdef CONFIG_HARDLOCKUP_DETECTOR
196static struct perf_event_attr wd_hw_attr = { 190static struct perf_event_attr wd_hw_attr = {
197 .type = PERF_TYPE_HARDWARE, 191 .type = PERF_TYPE_HARDWARE,
@@ -202,10 +196,13 @@ static struct perf_event_attr wd_hw_attr = {
202}; 196};
203 197
204/* Callback function for perf event subsystem */ 198/* Callback function for perf event subsystem */
205void watchdog_overflow_callback(struct perf_event *event, int nmi, 199static void watchdog_overflow_callback(struct perf_event *event, int nmi,
206 struct perf_sample_data *data, 200 struct perf_sample_data *data,
207 struct pt_regs *regs) 201 struct pt_regs *regs)
208{ 202{
203 /* Ensure the watchdog never gets throttled */
204 event->hw.interrupts = 0;
205
209 if (__get_cpu_var(watchdog_nmi_touch) == true) { 206 if (__get_cpu_var(watchdog_nmi_touch) == true) {
210 __get_cpu_var(watchdog_nmi_touch) = false; 207 __get_cpu_var(watchdog_nmi_touch) = false;
211 return; 208 return;
@@ -361,14 +358,14 @@ static int watchdog_nmi_enable(int cpu)
361 /* Try to register using hardware perf events */ 358 /* Try to register using hardware perf events */
362 wd_attr = &wd_hw_attr; 359 wd_attr = &wd_hw_attr;
363 wd_attr->sample_period = hw_nmi_get_sample_period(); 360 wd_attr->sample_period = hw_nmi_get_sample_period();
364 event = perf_event_create_kernel_counter(wd_attr, cpu, -1, watchdog_overflow_callback); 361 event = perf_event_create_kernel_counter(wd_attr, cpu, NULL, watchdog_overflow_callback);
365 if (!IS_ERR(event)) { 362 if (!IS_ERR(event)) {
366 printk(KERN_INFO "NMI watchdog enabled, takes one hw-pmu counter.\n"); 363 printk(KERN_INFO "NMI watchdog enabled, takes one hw-pmu counter.\n");
367 goto out_save; 364 goto out_save;
368 } 365 }
369 366
370 printk(KERN_ERR "NMI watchdog failed to create perf event on cpu%i: %p\n", cpu, event); 367 printk(KERN_ERR "NMI watchdog failed to create perf event on cpu%i: %p\n", cpu, event);
371 return -1; 368 return PTR_ERR(event);
372 369
373 /* success path */ 370 /* success path */
374out_save: 371out_save:
@@ -412,17 +409,19 @@ static int watchdog_prepare_cpu(int cpu)
412static int watchdog_enable(int cpu) 409static int watchdog_enable(int cpu)
413{ 410{
414 struct task_struct *p = per_cpu(softlockup_watchdog, cpu); 411 struct task_struct *p = per_cpu(softlockup_watchdog, cpu);
412 int err;
415 413
416 /* enable the perf event */ 414 /* enable the perf event */
417 if (watchdog_nmi_enable(cpu) != 0) 415 err = watchdog_nmi_enable(cpu);
418 return -1; 416 if (err)
417 return err;
419 418
420 /* create the watchdog thread */ 419 /* create the watchdog thread */
421 if (!p) { 420 if (!p) {
422 p = kthread_create(watchdog, (void *)(unsigned long)cpu, "watchdog/%d", cpu); 421 p = kthread_create(watchdog, (void *)(unsigned long)cpu, "watchdog/%d", cpu);
423 if (IS_ERR(p)) { 422 if (IS_ERR(p)) {
424 printk(KERN_ERR "softlockup watchdog for %i failed\n", cpu); 423 printk(KERN_ERR "softlockup watchdog for %i failed\n", cpu);
425 return -1; 424 return PTR_ERR(p);
426 } 425 }
427 kthread_bind(p, cpu); 426 kthread_bind(p, cpu);
428 per_cpu(watchdog_touch_ts, cpu) = 0; 427 per_cpu(watchdog_touch_ts, cpu) = 0;
@@ -430,6 +429,9 @@ static int watchdog_enable(int cpu)
430 wake_up_process(p); 429 wake_up_process(p);
431 } 430 }
432 431
432 /* if any cpu succeeds, watchdog is considered enabled for the system */
433 watchdog_enabled = 1;
434
433 return 0; 435 return 0;
434} 436}
435 437
@@ -452,9 +454,6 @@ static void watchdog_disable(int cpu)
452 per_cpu(softlockup_watchdog, cpu) = NULL; 454 per_cpu(softlockup_watchdog, cpu) = NULL;
453 kthread_stop(p); 455 kthread_stop(p);
454 } 456 }
455
456 /* if any cpu succeeds, watchdog is considered enabled for the system */
457 watchdog_enabled = 1;
458} 457}
459 458
460static void watchdog_enable_all_cpus(void) 459static void watchdog_enable_all_cpus(void)
@@ -474,6 +473,9 @@ static void watchdog_disable_all_cpus(void)
474{ 473{
475 int cpu; 474 int cpu;
476 475
476 if (no_watchdog)
477 return;
478
477 for_each_online_cpu(cpu) 479 for_each_online_cpu(cpu)
478 watchdog_disable(cpu); 480 watchdog_disable(cpu);
479 481
@@ -516,17 +518,16 @@ static int __cpuinit
516cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu) 518cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
517{ 519{
518 int hotcpu = (unsigned long)hcpu; 520 int hotcpu = (unsigned long)hcpu;
521 int err = 0;
519 522
520 switch (action) { 523 switch (action) {
521 case CPU_UP_PREPARE: 524 case CPU_UP_PREPARE:
522 case CPU_UP_PREPARE_FROZEN: 525 case CPU_UP_PREPARE_FROZEN:
523 if (watchdog_prepare_cpu(hotcpu)) 526 err = watchdog_prepare_cpu(hotcpu);
524 return NOTIFY_BAD;
525 break; 527 break;
526 case CPU_ONLINE: 528 case CPU_ONLINE:
527 case CPU_ONLINE_FROZEN: 529 case CPU_ONLINE_FROZEN:
528 if (watchdog_enable(hotcpu)) 530 err = watchdog_enable(hotcpu);
529 return NOTIFY_BAD;
530 break; 531 break;
531#ifdef CONFIG_HOTPLUG_CPU 532#ifdef CONFIG_HOTPLUG_CPU
532 case CPU_UP_CANCELED: 533 case CPU_UP_CANCELED:
@@ -539,7 +540,7 @@ cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
539 break; 540 break;
540#endif /* CONFIG_HOTPLUG_CPU */ 541#endif /* CONFIG_HOTPLUG_CPU */
541 } 542 }
542 return NOTIFY_OK; 543 return notifier_from_errno(err);
543} 544}
544 545
545static struct notifier_block __cpuinitdata cpu_nfb = { 546static struct notifier_block __cpuinitdata cpu_nfb = {
@@ -555,13 +556,11 @@ static int __init spawn_watchdog_task(void)
555 return 0; 556 return 0;
556 557
557 err = cpu_callback(&cpu_nfb, CPU_UP_PREPARE, cpu); 558 err = cpu_callback(&cpu_nfb, CPU_UP_PREPARE, cpu);
558 WARN_ON(err == NOTIFY_BAD); 559 WARN_ON(notifier_to_errno(err));
559 560
560 cpu_callback(&cpu_nfb, CPU_ONLINE, cpu); 561 cpu_callback(&cpu_nfb, CPU_ONLINE, cpu);
561 register_cpu_notifier(&cpu_nfb); 562 register_cpu_notifier(&cpu_nfb);
562 563
563 atomic_notifier_chain_register(&panic_notifier_list, &panic_block);
564
565 return 0; 564 return 0;
566} 565}
567early_initcall(spawn_watchdog_task); 566early_initcall(spawn_watchdog_task);