From a602accc3cd998cd060ad6aefc1d17abc9ce0109 Mon Sep 17 00:00:00 2001 From: Stephen Dickey Date: Tue, 30 Aug 2022 16:12:29 -0700 Subject: [PATCH] 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 --- kernel/sched/walt/walt_halt.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/kernel/sched/walt/walt_halt.c b/kernel/sched/walt/walt_halt.c index 663efed493c2..48a82da53cf5 100644 --- a/kernel/sched/walt/walt_halt.c +++ b/kernel/sched/walt/walt_halt.c @@ -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, ¶m); 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);