kernel/sched/walt: check migration disabled in allowed_ptr_locked

migrate_disable is called to prevent moving a task to a different
cpu. In the process it will update the task's cpus_ptr to a
temporary mask to restrict the task to run only on the current
cpu. It has only one cpu set in this new mask. migrate_disable
must always be paired with a migrate_enable call.

When migrate_enable is called it will attempt to manipulate the
allowed ptrs mask just prior to actually enabling migration on
a task. This means __set_cpus_allowed_ptr is called. This calls
a tracehook:

  migrate_enable
  __set_cpus_allowed_ptr
  __set_cpus_allowed_ptr_locked
  trace_android_rvh_set_cpus_allowed_ptr_locked
  android_rvh_set_cpus_allowed_ptr_locked

The purpose of handling this hook in walt, is to prevent the
assignment of a task to a halted cpu. When migrate_enable
restores the affinity to p->cpus_mask and p->cpus_mask consists
of a single cpu and that single cpu is halted, WALT will cause
__set_cpus_allowed_ptr to reject and return early. IOW
p->cpus_ptr is not set to p->cpus_mask.

If the p->cpus_ptr is not restored to point to the p->cpus_mask,
a subsequent migrate_disable/migrate_enable can happen, and
is allowed to happen with the runque lock taken. Since the
p->cpus_ptr is not pointing to the p->cpus_mask, migrate_enable
will incorrectly call __set_cpus_allowed_ptr. This in turn
will take the runque lock again resulting in a spinlock
recursion.

Address this by updating the hook code, checking the
migrate_disabled flag for the task, and allowing the existing
cpu to be used even if that cpu is halted. To achieve this
utilize a different hook that is present in the code already:
trace_android_rvh_set_cpus_allowed_by_task().

Change-Id: I42204332d708c6bc96f5de52eb9739d17cfdc0a3
Signed-off-by: Stephen Dickey <quic_dickey@quicinc.com>
This commit is contained in:
Stephen Dickey 2022-08-30 16:12:29 -07:00 committed by Sai Harshini Nimmala
parent 30c5ecaa7f
commit a602accc3c

View File

@ -500,17 +500,18 @@ static void android_rvh_get_nohz_timer_target(void *unused, int *cpu, bool *done
rcu_read_unlock();
}
static void android_rvh_set_cpus_allowed_ptr_locked(void *unused,
const struct cpumask *cpu_valid_mask,
const struct cpumask *new_mask,
unsigned int *dest_cpu)
static void android_rvh_set_cpus_allowed_by_task(void *unused,
const struct cpumask *cpu_valid_mask,
const struct cpumask *new_mask,
struct task_struct *p,
unsigned int *dest_cpu)
{
cpumask_t allowed_cpus;
if (unlikely(walt_disabled))
return;
if (cpu_halted(*dest_cpu)) {
if (cpu_halted(*dest_cpu) && !p->migration_disabled) {
/* remove halted cpus from the valid mask, and store locally */
cpumask_andnot(&allowed_cpus, cpu_valid_mask, cpu_halt_mask);
*dest_cpu = cpumask_any_and_distribute(&allowed_cpus, new_mask);
@ -573,8 +574,8 @@ void walt_halt_init(void)
sched_setscheduler_nocheck(walt_drain_thread, SCHED_FIFO, &param);
register_trace_android_rvh_get_nohz_timer_target(android_rvh_get_nohz_timer_target, NULL);
register_trace_android_rvh_set_cpus_allowed_ptr_locked(
android_rvh_set_cpus_allowed_ptr_locked, NULL);
register_trace_android_rvh_set_cpus_allowed_by_task(
android_rvh_set_cpus_allowed_by_task, NULL);
register_trace_android_rvh_rto_next_cpu(android_rvh_rto_next_cpu, NULL);
register_trace_android_rvh_is_cpu_allowed(android_rvh_is_cpu_allowed, NULL);