blob: fde8c499ffcc21fb2f62c6646df63f11a45a58b2 [file] [log] [blame]
From a90db8ff845312a69ec48d2f5668aa9644cbe0c4 Mon Sep 17 00:00:00 2001
From: Syed Rameez Mustafa <rameezmustafa@codeaurora.org>
Date: Fri, 16 Dec 2016 11:59:05 -0800
Subject: [PATCH] NOUPSTREAM: ANDROID: cpu-hotplug: Always use real time
scheduling when hotplugging a CPU
CPU hotplug operations take place in preemptible context. This leaves
the hotplugging thread at the mercy of overall system load and CPU
availability. If the hotplugging thread does not get an opportunity
to execute after it has already begun a hotplug operation, CPUs can
end up being stuck in a quasi online state. In the worst case a CPU
can be stuck in a state where the migration thread is parked while
another task is executing and changing affinity in a loop. This
combination can result in unbounded execution time for the running
task until the hotplugging thread gets the chance to run to complete
the hotplug operation.
Fix the said problem by ensuring that hotplug can only occur from
threads belonging to the RT sched class. This allows the hotplugging
thread priority on the CPU no matter what the system load or the
number of available CPUs are. If a SCHED_NORMAL task attempts to
hotplug a CPU, we temporarily elevate it's scheduling policy to RT.
Furthermore, we disallow hotplugging operations to begin if the
calling task belongs to the idle and deadline classes or those that
use the SCHED_BATCH policy.
[CPNOTE: 30/06/21] Lee: Vendor workaround - asked if this is still required via the bug
[CPNOTE: 30/09/21] Lee: Still no answer - if no one replies we should try and revert his 5 year old patch
Bug: 169238689
Change-Id: Idbb1384626e6ddff46c0d2ce752eee68396c78af
Signed-off-by: Syed Rameez Mustafa <rameezmustafa@codeaurora.org>
[psodagud@codeaurora.org: Fixed compilation issues]
Signed-off-by: Prasad Sodagudi <psodagud@codeaurora.org>
---
kernel/cpu.c | 43 ++++++++++++++++++++++++++++++++++++++++++-
kernel/sched/fair.c | 3 ++-
2 files changed, 44 insertions(+), 2 deletions(-)
diff --git a/kernel/cpu.c b/kernel/cpu.c
index ded343fa13a4..0fb2d33e62d3 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -34,6 +34,7 @@
#include <linux/scs.h>
#include <linux/percpu-rwsem.h>
#include <linux/cpuset.h>
+#include <uapi/linux/sched/types.h>
#include <linux/random.h>
#include <trace/events/power.h>
@@ -1320,6 +1321,25 @@ void cpuhp_online_idle(enum cpuhp_state state)
complete_ap_thread(st, true);
}
+static int switch_to_rt_policy(void)
+{
+ struct sched_param param = { .sched_priority = MAX_RT_PRIO - 1 };
+ unsigned int policy = current->policy;
+
+ if (policy == SCHED_NORMAL)
+ /* Switch to SCHED_FIFO from SCHED_NORMAL. */
+ return sched_setscheduler_nocheck(current, SCHED_FIFO, &param);
+ else
+ return 1;
+}
+
+static int switch_to_fair_policy(void)
+{
+ struct sched_param param = { .sched_priority = 0 };
+
+ return sched_setscheduler_nocheck(current, SCHED_NORMAL, &param);
+}
+
/* Requires cpu_add_remove_lock to be held */
static int _cpu_up(unsigned int cpu, int tasks_frozen, enum cpuhp_state target)
{
@@ -1384,6 +1404,7 @@ static int _cpu_up(unsigned int cpu, int tasks_frozen, enum cpuhp_state target)
static int cpu_up(unsigned int cpu, enum cpuhp_state target)
{
int err = 0;
+ int switch_err;
if (!cpu_possible(cpu)) {
pr_err("can't online cpu %d because it is not configured as may-hotadd at boot time\n",
@@ -1394,9 +1415,21 @@ static int cpu_up(unsigned int cpu, enum cpuhp_state target)
return -EINVAL;
}
+ /*
+ * CPU hotplug operations consists of many steps and each step
+ * calls a callback of core kernel subsystem. CPU hotplug-in
+ * operation may get preempted by other CFS tasks and whole
+ * operation of cpu hotplug in CPU gets delayed. Switch the
+ * current task to SCHED_FIFO from SCHED_NORMAL, so that
+ * hotplug in operation may complete quickly in heavy loaded
+ * conditions and new CPU will start handle the workload.
+ */
+
+ switch_err = switch_to_rt_policy();
+
err = try_online_node(cpu_to_node(cpu));
if (err)
- return err;
+ goto switch_out;
cpu_maps_update_begin();
@@ -1412,6 +1445,14 @@ static int cpu_up(unsigned int cpu, enum cpuhp_state target)
err = _cpu_up(cpu, 0, target);
out:
cpu_maps_update_done();
+switch_out:
+ if (!switch_err) {
+ switch_err = switch_to_fair_policy();
+ if (switch_err)
+ pr_err("Hotplug policy switch err=%d Task %s pid=%d\n",
+ switch_err, current->comm, current->pid);
+ }
+
return err;
}
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index 9fa41b8fbde1..e433ba2723f0 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -6803,7 +6803,8 @@ static int find_energy_efficient_cpu(struct task_struct *p, int prev_cpu, int sy
cpu = smp_processor_id();
if (sync && cpu_rq(cpu)->nr_running == 1 &&
- cpumask_test_cpu(cpu, p->cpus_ptr)) {
+ cpumask_test_cpu(cpu, p->cpus_ptr) &&
+ task_fits_capacity(p, capacity_of(cpu))) {
rcu_read_unlock();
return cpu;
}
--
2.35.0