Skip to content

Commit

Permalink
kernel/watchdog.c: control hard lockup detection default
Browse files Browse the repository at this point in the history
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.

[[email protected]: fix build]
[[email protected]: fix compile issues on sparc]
Signed-off-by: Ulrich Obergfell <[email protected]>
Signed-off-by: Andrew Jones <[email protected]>
Signed-off-by: Don Zickus <[email protected]>
Signed-off-by: Don Zickus <[email protected]>
Cc: Stephen Rothwell <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
rh-ulrich-o authored and torvalds committed Oct 14, 2014
1 parent 8a1db92 commit 6e7458a
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 2 deletions.
13 changes: 13 additions & 0 deletions include/linux/nmi.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,19 @@ static inline void touch_nmi_watchdog(void)
}
#endif

#if defined(CONFIG_HARDLOCKUP_DETECTOR)
extern void watchdog_enable_hardlockup_detector(bool val);
extern bool watchdog_hardlockup_detector_is_enabled(void);
#else
static inline void watchdog_enable_hardlockup_detector(bool val)
{
}
static inline bool watchdog_hardlockup_detector_is_enabled(void)
{
return true;
}
#endif

/*
* Create trigger_all_cpu_backtrace() out of the arch-provided
* base function. Return whether such support was available,
Expand Down
50 changes: 48 additions & 2 deletions kernel/watchdog.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,25 @@ static unsigned long soft_lockup_nmi_warn;
static int hardlockup_panic =
CONFIG_BOOTPARAM_HARDLOCKUP_PANIC_VALUE;

static bool hardlockup_detector_enabled = true;
/*
* We may not want to enable hard lockup detection by default in all cases,
* for example when running the kernel as a guest on a hypervisor. In these
* cases this function can be called to disable hard lockup detection. This
* function should only be executed once by the boot processor before the
* kernel command line parameters are parsed, because otherwise it is not
* possible to override this in hardlockup_panic_setup().
*/
void watchdog_enable_hardlockup_detector(bool val)
{
hardlockup_detector_enabled = val;
}

bool watchdog_hardlockup_detector_is_enabled(void)
{
return hardlockup_detector_enabled;
}

static int __init hardlockup_panic_setup(char *str)
{
if (!strncmp(str, "panic", 5))
Expand All @@ -67,6 +86,14 @@ static int __init hardlockup_panic_setup(char *str)
hardlockup_panic = 0;
else if (!strncmp(str, "0", 1))
watchdog_user_enabled = 0;
else if (!strncmp(str, "1", 1) || !strncmp(str, "2", 1)) {
/*
* Setting 'nmi_watchdog=1' or 'nmi_watchdog=2' (legacy option)
* has the same effect.
*/
watchdog_user_enabled = 1;
watchdog_enable_hardlockup_detector(true);
}
return 1;
}
__setup("nmi_watchdog=", hardlockup_panic_setup);
Expand Down Expand Up @@ -465,6 +492,15 @@ static int watchdog_nmi_enable(unsigned int cpu)
struct perf_event_attr *wd_attr;
struct perf_event *event = per_cpu(watchdog_ev, cpu);

/*
* Some kernels need to default hard lockup detection to
* 'disabled', for example a guest on a hypervisor.
*/
if (!watchdog_hardlockup_detector_is_enabled()) {
event = ERR_PTR(-ENOENT);
goto handle_err;
}

/* is it already setup and enabled? */
if (event && event->state > PERF_EVENT_STATE_OFF)
goto out;
Expand All @@ -479,6 +515,7 @@ static int watchdog_nmi_enable(unsigned int cpu)
/* Try to register using hardware perf events */
event = perf_event_create_kernel_counter(wd_attr, cpu, NULL, watchdog_overflow_callback, NULL);

handle_err:
/* save cpu0 error for future comparision */
if (cpu == 0 && IS_ERR(event))
cpu0_err = PTR_ERR(event);
Expand Down Expand Up @@ -624,11 +661,13 @@ int proc_dowatchdog(struct ctl_table *table, int write,
void __user *buffer, size_t *lenp, loff_t *ppos)
{
int err, old_thresh, old_enabled;
bool old_hardlockup;
static DEFINE_MUTEX(watchdog_proc_mutex);

mutex_lock(&watchdog_proc_mutex);
old_thresh = ACCESS_ONCE(watchdog_thresh);
old_enabled = ACCESS_ONCE(watchdog_user_enabled);
old_hardlockup = watchdog_hardlockup_detector_is_enabled();

err = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
if (err || !write)
Expand All @@ -640,15 +679,22 @@ int proc_dowatchdog(struct ctl_table *table, int write,
* disabled. The 'watchdog_running' variable check in
* watchdog_*_all_cpus() function takes care of this.
*/
if (watchdog_user_enabled && watchdog_thresh)
if (watchdog_user_enabled && watchdog_thresh) {
/*
* Prevent a change in watchdog_thresh accidentally overriding
* the enablement of the hardlockup detector.
*/
if (watchdog_user_enabled != old_enabled)
watchdog_enable_hardlockup_detector(true);
err = watchdog_enable_all_cpus(old_thresh != watchdog_thresh);
else
} else
watchdog_disable_all_cpus();

/* Restore old values on failure */
if (err) {
watchdog_thresh = old_thresh;
watchdog_user_enabled = old_enabled;
watchdog_enable_hardlockup_detector(old_hardlockup);
}
out:
mutex_unlock(&watchdog_proc_mutex);
Expand Down

0 comments on commit 6e7458a

Please sign in to comment.