diff options
| author | Linux Build Service Account <lnxbuild@localhost> | 2016-11-08 11:19:07 -0800 |
|---|---|---|
| committer | Gerrit - the friendly Code Review server <code-review@localhost> | 2016-11-08 11:19:07 -0800 |
| commit | a97a6be4ded3ba9fe4aea96fe6ed747612e9732f (patch) | |
| tree | 4ca3e6fd0e65cb7b6853bb3e3ba65d1d9bd6ec59 /kernel | |
| parent | 5a1e6a8dbf21e76ffb45f480eea21ab04bc2cce6 (diff) | |
| parent | af04b3a2bad55cbe37b013a41469fabecbf5636f (diff) | |
Merge "sched: Ensure watchdog is enabled before disabling"
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/sched/core.c | 16 | ||||
| -rw-r--r-- | kernel/watchdog.c | 28 |
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, ¶m); } -/* 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) |
