]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
sched_ext: Don't enable non-ext tasks in the sub-sched task loops
authorTejun Heo <tj@kernel.org>
Thu, 16 Jul 2026 20:46:04 +0000 (10:46 -1000)
committerTejun Heo <tj@kernel.org>
Sat, 18 Jul 2026 07:29:27 +0000 (21:29 -1000)
Root enable and scx_post_fork() enable a task only if it's on the ext class.
Tasks on other classes, possible under an SCX_OPS_SWITCH_PARTIAL root, are
left READY and enabled by switching_to_scx() when they switch over. The sub
enable-commit pass and the sub-disable re-home loop enable unconditionally,
so a fair-class READY task in the subtree becomes ENABLED while not on
sched_ext. A later switch to SCHED_EXT then trips the task state validation
WARN (ENABLED with the previous state not READY) and calls ops.enable() a
second time.

Gate scx_enable_task() on the task's class in both loops.

Fixes: 337ec00b1d9c ("sched_ext: Implement cgroup sub-sched enabling and disabling")
Signed-off-by: Tejun Heo <tj@kernel.org>
Reviewed-by: Andrea Righi <arighi@nvidia.com>
kernel/sched/ext/ext.c

index 98dd7df88db41cdfff91ec17db89b1e8b20c5d86..18183062f751c9c527da710af1b64cea09360516 100644 (file)
@@ -6010,15 +6010,22 @@ static void scx_sub_disable(struct scx_sched *sch)
                        /*
                         * $p is initialized for $parent and still attached to
                         * @sch. Disable and exit for @sch, switch over to
-                        * $parent, override the state to READY to account for
-                        * $p having already been initialized, and then enable.
+                        * $parent and override the state to READY to account
+                        * for $p having already been initialized.
                         */
                        scx_disable_and_exit_task(sch, p);
                        scx_set_task_state(p, SCX_TASK_INIT_BEGIN);
                        scx_set_task_state(p, SCX_TASK_INIT);
                        scx_set_task_sched(p, parent);
                        scx_set_task_state(p, SCX_TASK_READY);
-                       scx_enable_task(parent, p);
+
+                       /*
+                        * A task on a non-ext class, possible under an
+                        * %SCX_OPS_SWITCH_PARTIAL root, stays READY and is
+                        * enabled by switching_to_scx() if it switches over.
+                        */
+                       if (p->sched_class == &ext_sched_class)
+                               scx_enable_task(parent, p);
                }
 
                task_rq_unlock(rq, p, &rf);
@@ -7726,10 +7733,14 @@ static void scx_sub_enable_workfn(struct kthread_work *work)
 
                        /*
                         * $p is now only initialized for @sch and READY, which
-                        * is what we want. Assign it to @sch and enable.
+                        * is what we want. Assign it to @sch and, if it's on
+                        * the ext class, enable. A non-ext task, possible under
+                        * an %SCX_OPS_SWITCH_PARTIAL root, stays READY and is
+                        * enabled by switching_to_scx() if it switches over.
                         */
                        scx_set_task_sched(p, sch);
-                       scx_enable_task(sch, p);
+                       if (p->sched_class == &ext_sched_class)
+                               scx_enable_task(sch, p);
 
                        p->scx.flags &= ~SCX_TASK_SUB_INIT;
                }