diff options
author | Ulrich Obergfell <uobergfe@redhat.com> | 2014-10-13 18:55:35 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-10-13 20:18:27 -0400 |
commit | 6e7458a6f074c71e74cda31c483114e65ea0f570 (patch) | |
tree | d942b6b9ec308d66f64649b94d088b02bf2e6309 /kernel/watchdog.c | |
parent | 8a1db92830d0a71e1429725992eb91470214c820 (diff) |
kernel/watchdog.c: control hard lockup detection default
In some cases we don't want hard lockup detection enabled by default.
An example is when running as a guest. Introduce
watchdog_enable_hardlockup_detector(bool)
allowing those cases to disable hard lockup detection. This must be
executed early by the boot processor from e.g. smp_prepare_boot_cpu, in
order to allow kernel command line arguments to override it, as well as
to avoid hard lockup detection being enabled before we've had a chance
to indicate that it's unwanted. In summary,
initial boot: default=enabled
smp_prepare_boot_cpu
watchdog_enable_hardlockup_detector(false): default=disabled
cmdline has 'nmi_watchdog=1': default=enabled
The running kernel still has the ability to enable/disable at any time
with /proc/sys/kernel/nmi_watchdog us usual. However even when the
default has been overridden /proc/sys/kernel/nmi_watchdog will initially
show '1'. To truly turn it on one must disable/enable it, i.e.
echo 0 > /proc/sys/kernel/nmi_watchdog
echo 1 > /proc/sys/kernel/nmi_watchdog
This patch will be immediately useful for KVM with the next patch of this
series. Other hypervisor guest types may find it useful as well.
[akpm@linux-foundation.org: fix build]
[dzickus@redhat.com: fix compile issues on sparc]
Signed-off-by: Ulrich Obergfell <uobergfe@redhat.com>
Signed-off-by: Andrew Jones <drjones@redhat.com>
Signed-off-by: Don Zickus <dzickus@redhat.com>
Signed-off-by: Don Zickus <dzickus@redhat.com>
Cc: Stephen Rothwell <sfr@canb.auug.org.au>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'kernel/watchdog.c')
-rw-r--r-- | kernel/watchdog.c | 50 |
1 files changed, 48 insertions, 2 deletions
diff --git a/kernel/watchdog.c b/kernel/watchdog.c index ff7fd80bef99..49e9537f3673 100644 --- a/kernel/watchdog.c +++ b/kernel/watchdog.c | |||
@@ -59,6 +59,25 @@ static unsigned long soft_lockup_nmi_warn; | |||
59 | static int hardlockup_panic = | 59 | static int hardlockup_panic = |
60 | CONFIG_BOOTPARAM_HARDLOCKUP_PANIC_VALUE; | 60 | CONFIG_BOOTPARAM_HARDLOCKUP_PANIC_VALUE; |
61 | 61 | ||
62 | static bool hardlockup_detector_enabled = true; | ||
63 | /* | ||
64 | * We may not want to enable hard lockup detection by default in all cases, | ||
65 | * for example when running the kernel as a guest on a hypervisor. In these | ||
66 | * cases this function can be called to disable hard lockup detection. This | ||
67 | * function should only be executed once by the boot processor before the | ||
68 | * kernel command line parameters are parsed, because otherwise it is not | ||
69 | * possible to override this in hardlockup_panic_setup(). | ||
70 | */ | ||
71 | void watchdog_enable_hardlockup_detector(bool val) | ||
72 | { | ||
73 | hardlockup_detector_enabled = val; | ||
74 | } | ||
75 | |||
76 | bool watchdog_hardlockup_detector_is_enabled(void) | ||
77 | { | ||
78 | return hardlockup_detector_enabled; | ||
79 | } | ||
80 | |||
62 | static int __init hardlockup_panic_setup(char *str) | 81 | static int __init hardlockup_panic_setup(char *str) |
63 | { | 82 | { |
64 | if (!strncmp(str, "panic", 5)) | 83 | if (!strncmp(str, "panic", 5)) |
@@ -67,6 +86,14 @@ static int __init hardlockup_panic_setup(char *str) | |||
67 | hardlockup_panic = 0; | 86 | hardlockup_panic = 0; |
68 | else if (!strncmp(str, "0", 1)) | 87 | else if (!strncmp(str, "0", 1)) |
69 | watchdog_user_enabled = 0; | 88 | watchdog_user_enabled = 0; |
89 | else if (!strncmp(str, "1", 1) || !strncmp(str, "2", 1)) { | ||
90 | /* | ||
91 | * Setting 'nmi_watchdog=1' or 'nmi_watchdog=2' (legacy option) | ||
92 | * has the same effect. | ||
93 | */ | ||
94 | watchdog_user_enabled = 1; | ||
95 | watchdog_enable_hardlockup_detector(true); | ||
96 | } | ||
70 | return 1; | 97 | return 1; |
71 | } | 98 | } |
72 | __setup("nmi_watchdog=", hardlockup_panic_setup); | 99 | __setup("nmi_watchdog=", hardlockup_panic_setup); |
@@ -465,6 +492,15 @@ static int watchdog_nmi_enable(unsigned int cpu) | |||
465 | struct perf_event_attr *wd_attr; | 492 | struct perf_event_attr *wd_attr; |
466 | struct perf_event *event = per_cpu(watchdog_ev, cpu); | 493 | struct perf_event *event = per_cpu(watchdog_ev, cpu); |
467 | 494 | ||
495 | /* | ||
496 | * Some kernels need to default hard lockup detection to | ||
497 | * 'disabled', for example a guest on a hypervisor. | ||
498 | */ | ||
499 | if (!watchdog_hardlockup_detector_is_enabled()) { | ||
500 | event = ERR_PTR(-ENOENT); | ||
501 | goto handle_err; | ||
502 | } | ||
503 | |||
468 | /* is it already setup and enabled? */ | 504 | /* is it already setup and enabled? */ |
469 | if (event && event->state > PERF_EVENT_STATE_OFF) | 505 | if (event && event->state > PERF_EVENT_STATE_OFF) |
470 | goto out; | 506 | goto out; |
@@ -479,6 +515,7 @@ static int watchdog_nmi_enable(unsigned int cpu) | |||
479 | /* Try to register using hardware perf events */ | 515 | /* Try to register using hardware perf events */ |
480 | event = perf_event_create_kernel_counter(wd_attr, cpu, NULL, watchdog_overflow_callback, NULL); | 516 | event = perf_event_create_kernel_counter(wd_attr, cpu, NULL, watchdog_overflow_callback, NULL); |
481 | 517 | ||
518 | handle_err: | ||
482 | /* save cpu0 error for future comparision */ | 519 | /* save cpu0 error for future comparision */ |
483 | if (cpu == 0 && IS_ERR(event)) | 520 | if (cpu == 0 && IS_ERR(event)) |
484 | cpu0_err = PTR_ERR(event); | 521 | cpu0_err = PTR_ERR(event); |
@@ -624,11 +661,13 @@ int proc_dowatchdog(struct ctl_table *table, int write, | |||
624 | void __user *buffer, size_t *lenp, loff_t *ppos) | 661 | void __user *buffer, size_t *lenp, loff_t *ppos) |
625 | { | 662 | { |
626 | int err, old_thresh, old_enabled; | 663 | int err, old_thresh, old_enabled; |
664 | bool old_hardlockup; | ||
627 | static DEFINE_MUTEX(watchdog_proc_mutex); | 665 | static DEFINE_MUTEX(watchdog_proc_mutex); |
628 | 666 | ||
629 | mutex_lock(&watchdog_proc_mutex); | 667 | mutex_lock(&watchdog_proc_mutex); |
630 | old_thresh = ACCESS_ONCE(watchdog_thresh); | 668 | old_thresh = ACCESS_ONCE(watchdog_thresh); |
631 | old_enabled = ACCESS_ONCE(watchdog_user_enabled); | 669 | old_enabled = ACCESS_ONCE(watchdog_user_enabled); |
670 | old_hardlockup = watchdog_hardlockup_detector_is_enabled(); | ||
632 | 671 | ||
633 | err = proc_dointvec_minmax(table, write, buffer, lenp, ppos); | 672 | err = proc_dointvec_minmax(table, write, buffer, lenp, ppos); |
634 | if (err || !write) | 673 | if (err || !write) |
@@ -640,15 +679,22 @@ int proc_dowatchdog(struct ctl_table *table, int write, | |||
640 | * disabled. The 'watchdog_running' variable check in | 679 | * disabled. The 'watchdog_running' variable check in |
641 | * watchdog_*_all_cpus() function takes care of this. | 680 | * watchdog_*_all_cpus() function takes care of this. |
642 | */ | 681 | */ |
643 | if (watchdog_user_enabled && watchdog_thresh) | 682 | if (watchdog_user_enabled && watchdog_thresh) { |
683 | /* | ||
684 | * Prevent a change in watchdog_thresh accidentally overriding | ||
685 | * the enablement of the hardlockup detector. | ||
686 | */ | ||
687 | if (watchdog_user_enabled != old_enabled) | ||
688 | watchdog_enable_hardlockup_detector(true); | ||
644 | err = watchdog_enable_all_cpus(old_thresh != watchdog_thresh); | 689 | err = watchdog_enable_all_cpus(old_thresh != watchdog_thresh); |
645 | else | 690 | } else |
646 | watchdog_disable_all_cpus(); | 691 | watchdog_disable_all_cpus(); |
647 | 692 | ||
648 | /* Restore old values on failure */ | 693 | /* Restore old values on failure */ |
649 | if (err) { | 694 | if (err) { |
650 | watchdog_thresh = old_thresh; | 695 | watchdog_thresh = old_thresh; |
651 | watchdog_user_enabled = old_enabled; | 696 | watchdog_user_enabled = old_enabled; |
697 | watchdog_enable_hardlockup_detector(old_hardlockup); | ||
652 | } | 698 | } |
653 | out: | 699 | out: |
654 | mutex_unlock(&watchdog_proc_mutex); | 700 | mutex_unlock(&watchdog_proc_mutex); |