|
@@ -31,7 +31,7 @@
|
|
|
|
|
|
int watchdog_enabled = 1;
|
|
|
int __read_mostly watchdog_thresh = 10;
|
|
|
-static int __read_mostly watchdog_disabled;
|
|
|
+static int __read_mostly watchdog_disabled = 1;
|
|
|
static u64 __read_mostly sample_period;
|
|
|
|
|
|
static DEFINE_PER_CPU(unsigned long, watchdog_touch_ts);
|
|
@@ -347,11 +347,6 @@ static void watchdog_enable(unsigned int cpu)
|
|
|
hrtimer_init(hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
|
|
|
hrtimer->function = watchdog_timer_fn;
|
|
|
|
|
|
- if (!watchdog_enabled) {
|
|
|
- kthread_park(current);
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
/* Enable the perf event */
|
|
|
watchdog_nmi_enable(cpu);
|
|
|
|
|
@@ -374,6 +369,11 @@ static void watchdog_disable(unsigned int cpu)
|
|
|
watchdog_nmi_disable(cpu);
|
|
|
}
|
|
|
|
|
|
+static void watchdog_cleanup(unsigned int cpu, bool online)
|
|
|
+{
|
|
|
+ watchdog_disable(cpu);
|
|
|
+}
|
|
|
+
|
|
|
static int watchdog_should_run(unsigned int cpu)
|
|
|
{
|
|
|
return __this_cpu_read(hrtimer_interrupts) !=
|
|
@@ -475,28 +475,40 @@ static int watchdog_nmi_enable(unsigned int cpu) { return 0; }
|
|
|
static void watchdog_nmi_disable(unsigned int cpu) { return; }
|
|
|
#endif /* CONFIG_HARDLOCKUP_DETECTOR */
|
|
|
|
|
|
-/* prepare/enable/disable routines */
|
|
|
-/* sysctl functions */
|
|
|
-#ifdef CONFIG_SYSCTL
|
|
|
-static void watchdog_enable_all_cpus(void)
|
|
|
+static struct smp_hotplug_thread watchdog_threads = {
|
|
|
+ .store = &softlockup_watchdog,
|
|
|
+ .thread_should_run = watchdog_should_run,
|
|
|
+ .thread_fn = watchdog,
|
|
|
+ .thread_comm = "watchdog/%u",
|
|
|
+ .setup = watchdog_enable,
|
|
|
+ .cleanup = watchdog_cleanup,
|
|
|
+ .park = watchdog_disable,
|
|
|
+ .unpark = watchdog_enable,
|
|
|
+};
|
|
|
+
|
|
|
+static int watchdog_enable_all_cpus(void)
|
|
|
{
|
|
|
- unsigned int cpu;
|
|
|
+ int err = 0;
|
|
|
|
|
|
if (watchdog_disabled) {
|
|
|
- watchdog_disabled = 0;
|
|
|
- for_each_online_cpu(cpu)
|
|
|
- kthread_unpark(per_cpu(softlockup_watchdog, cpu));
|
|
|
+ err = smpboot_register_percpu_thread(&watchdog_threads);
|
|
|
+ if (err)
|
|
|
+ pr_err("Failed to create watchdog threads, disabled\n");
|
|
|
+ else
|
|
|
+ watchdog_disabled = 0;
|
|
|
}
|
|
|
+
|
|
|
+ return err;
|
|
|
}
|
|
|
|
|
|
+/* prepare/enable/disable routines */
|
|
|
+/* sysctl functions */
|
|
|
+#ifdef CONFIG_SYSCTL
|
|
|
static void watchdog_disable_all_cpus(void)
|
|
|
{
|
|
|
- unsigned int cpu;
|
|
|
-
|
|
|
if (!watchdog_disabled) {
|
|
|
watchdog_disabled = 1;
|
|
|
- for_each_online_cpu(cpu)
|
|
|
- kthread_park(per_cpu(softlockup_watchdog, cpu));
|
|
|
+ smpboot_unregister_percpu_thread(&watchdog_threads);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -507,14 +519,14 @@ static void watchdog_disable_all_cpus(void)
|
|
|
int proc_dowatchdog(struct ctl_table *table, int write,
|
|
|
void __user *buffer, size_t *lenp, loff_t *ppos)
|
|
|
{
|
|
|
- int ret;
|
|
|
+ int err, old_thresh, old_enabled;
|
|
|
|
|
|
- if (watchdog_disabled < 0)
|
|
|
- return -ENODEV;
|
|
|
+ old_thresh = ACCESS_ONCE(watchdog_thresh);
|
|
|
+ old_enabled = ACCESS_ONCE(watchdog_enabled);
|
|
|
|
|
|
- ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
|
|
|
- if (ret || !write)
|
|
|
- return ret;
|
|
|
+ err = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
|
|
|
+ if (err || !write)
|
|
|
+ return err;
|
|
|
|
|
|
set_sample_period();
|
|
|
/*
|
|
@@ -523,29 +535,24 @@ int proc_dowatchdog(struct ctl_table *table, int write,
|
|
|
* watchdog_*_all_cpus() function takes care of this.
|
|
|
*/
|
|
|
if (watchdog_enabled && watchdog_thresh)
|
|
|
- watchdog_enable_all_cpus();
|
|
|
+ err = watchdog_enable_all_cpus();
|
|
|
else
|
|
|
watchdog_disable_all_cpus();
|
|
|
|
|
|
- return ret;
|
|
|
+ /* Restore old values on failure */
|
|
|
+ if (err) {
|
|
|
+ watchdog_thresh = old_thresh;
|
|
|
+ watchdog_enabled = old_enabled;
|
|
|
+ }
|
|
|
+
|
|
|
+ return err;
|
|
|
}
|
|
|
#endif /* CONFIG_SYSCTL */
|
|
|
|
|
|
-static struct smp_hotplug_thread watchdog_threads = {
|
|
|
- .store = &softlockup_watchdog,
|
|
|
- .thread_should_run = watchdog_should_run,
|
|
|
- .thread_fn = watchdog,
|
|
|
- .thread_comm = "watchdog/%u",
|
|
|
- .setup = watchdog_enable,
|
|
|
- .park = watchdog_disable,
|
|
|
- .unpark = watchdog_enable,
|
|
|
-};
|
|
|
-
|
|
|
void __init lockup_detector_init(void)
|
|
|
{
|
|
|
set_sample_period();
|
|
|
- if (smpboot_register_percpu_thread(&watchdog_threads)) {
|
|
|
- pr_err("Failed to create watchdog threads, disabled\n");
|
|
|
- watchdog_disabled = -ENODEV;
|
|
|
- }
|
|
|
+
|
|
|
+ if (watchdog_enabled)
|
|
|
+ watchdog_enable_all_cpus();
|
|
|
}
|