From 34c60754d33b16a289e616e49ba33483a5c1bc50 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 5 Mar 2024 10:46:36 -1000 Subject: [PATCH] scx: Fix scx_ops_bypass_depth going out of sync scx_pm_handler() skips calling scx_ops_bypass() if !scx_enabled(). This means that if a SCX scheduler is loaded while PM operation is in progress, we can get an unbalanced scx_ops_bypass(%false) and vice-versa, which is easy to trigger using /dev/snapshot. Let's fix it by: - Make scx_pm_handler() always call scx_ops_bypass(). - Synchronize scx_ops_bypass() against enable/disable path using scx_ops_enable_mutex and skip only the task update part when !scx_enabled(). Reported by @xingyiz in #153. --- kernel/sched/ext.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c index 31d8ed7584adf..d34271845f493 100644 --- a/kernel/sched/ext.c +++ b/kernel/sched/ext.c @@ -3218,6 +3218,10 @@ static void scx_ops_bypass(bool bypass) return; } + mutex_lock(&scx_ops_enable_mutex); + if (!scx_enabled()) + goto out_unlock; + /* * No task property is changing. We just need to make sure all currently * queued tasks are re-queued according to the new scx_ops_bypassing() @@ -3255,6 +3259,9 @@ static void scx_ops_bypass(bool bypass) /* kick to restore ticks */ resched_cpu(cpu); } + +out_unlock: + mutex_unlock(&scx_ops_enable_mutex); } static void free_exit_info(struct scx_exit_info *ei) @@ -4408,9 +4415,6 @@ void print_scx_info(const char *log_lvl, struct task_struct *p) static int scx_pm_handler(struct notifier_block *nb, unsigned long event, void *ptr) { - if (!scx_enabled()) - return NOTIFY_OK; - /* * SCX schedulers often have userspace components which are sometimes * involved in critial scheduling paths. PM operations involve freezing