Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5dba78f8 authored by Olav Haugan's avatar Olav Haugan Committed by Satya Durga Srinivasu Prabhala
Browse files

sched: Ensure watchdog is enabled before disabling



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.

Change-Id: I88f73603b6d389a46f8e819d9b490091d5ba4fe9
Signed-off-by: default avatarOlav Haugan <ohaugan@codeaurora.org>
[satyap@codeaurora.org: Port to 4.19 and resolve merge conflicts]
Signed-off-by: default avatarSatya Durga Srinivasu Prabhala <satyap@codeaurora.org>
parent b97b28e0
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
@@ -11,6 +11,7 @@

#include <linux/kcov.h>
#include <linux/irq.h>
#include <linux/delay.h>

#include <asm/switch_to.h>
#include <asm/tlb.h>
@@ -5975,6 +5976,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);

+20 −8
Original line number Diff line number Diff line
@@ -471,7 +471,6 @@ static enum hrtimer_restart watchdog_timer_fn(struct hrtimer *hrtimer)
	return HRTIMER_RESTART;
}

/* Must be called with hotplug lock (lock_device_hotplug()) held. */
void watchdog_enable(unsigned int cpu)
{
	struct hrtimer *hrtimer = this_cpu_ptr(&watchdog_hrtimer);
@@ -483,11 +482,8 @@ void watchdog_enable(unsigned int cpu)
	init_completion(done);
	complete(done);

	lock_device_hotplug_assert();

	if (*enabled)
		return;
	*enabled = 1;

	/*
	 * Start the timer first to prevent the NMI watchdog triggering
@@ -503,19 +499,24 @@ void watchdog_enable(unsigned int cpu)
	/* Enable the perf event */
	if (watchdog_enabled & NMI_WATCHDOG_ENABLED)
		watchdog_nmi_enable(cpu);

	/*
	 * 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 = this_cpu_ptr(&watchdog_hrtimer);
	unsigned int *enabled = this_cpu_ptr(&watchdog_en);

	lock_device_hotplug_assert();

	if (!*enabled)
		return;
	*enabled = 0;

	WARN_ON_ONCE(cpu != smp_processor_id());

@@ -527,6 +528,17 @@ void watchdog_disable(unsigned int cpu)
	watchdog_nmi_disable(cpu);
	hrtimer_cancel(hrtimer);
	wait_for_completion(this_cpu_ptr(&softlockup_completion));

	/*
	 * 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 int softlockup_stop_fn(void *data)