Skip to content

Commit 4269c60

Browse files
committed
sched_ext: Enable scx_ops_init_task() separately
scx_ops_init_task() and the follow-up scx_ops_enable_task() in the fork path were gated by scx_enabled() test and thus __scx_ops_enabled had to be turned on before the first scx_ops_init_task() loop in scx_ops_enable(). However, if an external entity causes sched_class switch before the loop is complete, tasks which are not initialized could be switched to SCX. The following can be reproduced by running a program which keeps toggling a process between SCHED_OTHER and SCHED_EXT using sched_setscheduler(2). sched_ext: Invalid task state transition 0 -> 3 for fish[1623] WARNING: CPU: 1 PID: 1650 at kernel/sched/ext.c:3392 scx_ops_enable_task+0x1a1/0x200 ... Sched_ext: simple (enabling) RIP: 0010:scx_ops_enable_task+0x1a1/0x200 ... switching_to_scx+0x13/0xa0 __sched_setscheduler+0x850/0xa50 do_sched_setscheduler+0x104/0x1c0 __x64_sys_sched_setscheduler+0x18/0x30 do_syscall_64+0x7b/0x140 entry_SYSCALL_64_after_hwframe+0x76/0x7e Fix it by gating scx_ops_init_task() separately using scx_ops_init_task_enabled. __scx_ops_enabled is now set after all tasks are finished with scx_ops_init_task(). Signed-off-by: Tejun Heo <[email protected]>
1 parent 9753358 commit 4269c60

File tree

1 file changed

+10
-4
lines changed

1 file changed

+10
-4
lines changed

kernel/sched/ext.c

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -853,6 +853,7 @@ DEFINE_STATIC_KEY_FALSE(__scx_ops_enabled);
853853
DEFINE_STATIC_PERCPU_RWSEM(scx_fork_rwsem);
854854
static atomic_t scx_ops_enable_state_var = ATOMIC_INIT(SCX_OPS_DISABLED);
855855
static atomic_t scx_ops_bypass_depth = ATOMIC_INIT(0);
856+
static bool scx_ops_init_task_enabled;
856857
static bool scx_switching_all;
857858
DEFINE_STATIC_KEY_FALSE(__scx_switched_all);
858859

@@ -3565,15 +3566,15 @@ int scx_fork(struct task_struct *p)
35653566
{
35663567
percpu_rwsem_assert_held(&scx_fork_rwsem);
35673568

3568-
if (scx_enabled())
3569+
if (scx_ops_init_task_enabled)
35693570
return scx_ops_init_task(p, task_group(p), true);
35703571
else
35713572
return 0;
35723573
}
35733574

35743575
void scx_post_fork(struct task_struct *p)
35753576
{
3576-
if (scx_enabled()) {
3577+
if (scx_ops_init_task_enabled) {
35773578
scx_set_task_state(p, SCX_TASK_READY);
35783579

35793580
/*
@@ -4453,6 +4454,8 @@ static void scx_ops_disable_workfn(struct kthread_work *work)
44534454
cpus_read_lock();
44544455
scx_cgroup_lock();
44554456

4457+
scx_ops_init_task_enabled = false;
4458+
44564459
spin_lock_irq(&scx_tasks_lock);
44574460
scx_task_iter_init(&sti);
44584461
/*
@@ -5132,7 +5135,8 @@ static int scx_ops_enable(struct sched_ext_ops *ops, struct bpf_link *link)
51325135
if (ret)
51335136
goto err_disable_unlock_all;
51345137

5135-
static_branch_enable_cpuslocked(&__scx_ops_enabled);
5138+
WARN_ON_ONCE(scx_ops_init_task_enabled);
5139+
scx_ops_init_task_enabled = true;
51365140

51375141
/*
51385142
* Enable ops for every task. Fork is excluded by scx_fork_rwsem
@@ -5175,9 +5179,11 @@ static int scx_ops_enable(struct sched_ext_ops *ops, struct bpf_link *link)
51755179
spin_unlock_irq(&scx_tasks_lock);
51765180

51775181
/*
5178-
* All tasks are prepped but the tasks are not enabled. Switch everyone.
5182+
* All tasks are READY. It's safe to turn on scx_enabled() and switch
5183+
* all eligible tasks.
51795184
*/
51805185
WRITE_ONCE(scx_switching_all, !(ops->flags & SCX_OPS_SWITCH_PARTIAL));
5186+
static_branch_enable_cpuslocked(&__scx_ops_enabled);
51815187

51825188
/*
51835189
* We're fully committed and can't fail. The task READY -> ENABLED

0 commit comments

Comments
 (0)