summaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
authorLinux Build Service Account <lnxbuild@localhost>2016-11-08 11:19:07 -0800
committerGerrit - the friendly Code Review server <code-review@localhost>2016-11-08 11:19:07 -0800
commita97a6be4ded3ba9fe4aea96fe6ed747612e9732f (patch)
tree4ca3e6fd0e65cb7b6853bb3e3ba65d1d9bd6ec59 /kernel
parent5a1e6a8dbf21e76ffb45f480eea21ab04bc2cce6 (diff)
parentaf04b3a2bad55cbe37b013a41469fabecbf5636f (diff)
Merge "sched: Ensure watchdog is enabled before disabling"
Diffstat (limited to 'kernel')
-rw-r--r--kernel/sched/core.c16
-rw-r--r--kernel/watchdog.c28
2 files changed, 36 insertions, 8 deletions
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index a1bb5d4a003c..e7196c3a3457 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -5696,6 +5696,22 @@ int sched_isolate_cpu(int cpu)
if (++cpu_isolation_vote[cpu] > 1)
goto out;
+ /*
+ * There is a race between watchdog being enabled by hotplug and
+ * core isolation disabling the watchdog. When a CPU is hotplugged in
+ * and the hotplug lock has been released the watchdog thread might
+ * not have run yet to enable the watchdog.
+ * We have to wait for the watchdog to be enabled before proceeding.
+ */
+ if (!watchdog_configured(cpu)) {
+ msleep(20);
+ if (!watchdog_configured(cpu)) {
+ --cpu_isolation_vote[cpu];
+ ret_code = -EBUSY;
+ goto out;
+ }
+ }
+
set_cpu_isolated(cpu, true);
cpumask_clear_cpu(cpu, &avail_cpus);
diff --git a/kernel/watchdog.c b/kernel/watchdog.c
index 7f21591c8ec5..f2813e137b23 100644
--- a/kernel/watchdog.c
+++ b/kernel/watchdog.c
@@ -588,17 +588,13 @@ static void watchdog_set_prio(unsigned int policy, unsigned int prio)
sched_setscheduler(current, policy, &param);
}
-/* Must be called with hotplug lock (lock_device_hotplug()) held. */
void watchdog_enable(unsigned int cpu)
{
struct hrtimer *hrtimer = raw_cpu_ptr(&watchdog_hrtimer);
unsigned int *enabled = raw_cpu_ptr(&watchdog_en);
- lock_device_hotplug_assert();
-
if (*enabled)
return;
- *enabled = 1;
/* kick off the timer for the hardlockup detector */
hrtimer_init(hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
@@ -614,24 +610,40 @@ void watchdog_enable(unsigned int cpu)
/* initialize timestamp */
watchdog_set_prio(SCHED_FIFO, MAX_RT_PRIO - 1);
__touch_watchdog();
+
+ /*
+ * Need to ensure above operations are observed by other CPUs before
+ * indicating that timer is enabled. This is to synchronize core
+ * isolation and hotplug. Core isolation will wait for this flag to be
+ * set.
+ */
+ mb();
+ *enabled = 1;
}
-/* Must be called with hotplug lock (lock_device_hotplug()) held. */
void watchdog_disable(unsigned int cpu)
{
struct hrtimer *hrtimer = raw_cpu_ptr(&watchdog_hrtimer);
unsigned int *enabled = raw_cpu_ptr(&watchdog_en);
- lock_device_hotplug_assert();
-
if (!*enabled)
return;
- *enabled = 0;
watchdog_set_prio(SCHED_NORMAL, 0);
hrtimer_cancel(hrtimer);
/* disable the perf event */
watchdog_nmi_disable(cpu);
+
+ /*
+ * No need for barrier here since disabling the watchdog is
+ * synchronized with hotplug lock
+ */
+ *enabled = 0;
+}
+
+bool watchdog_configured(unsigned int cpu)
+{
+ return *per_cpu_ptr(&watchdog_en, cpu);
}
static void watchdog_cleanup(unsigned int cpu, bool online)