Skip to content

Commit cd6aab7

Browse files
committed
sched_ext: Close sub-sched init race with post-init DEAD recheck
scx_sub_enable_workfn()'s init pass and scx_sub_disable() migration both drop the rq lock to call __scx_init_task() against the other sched. A TASK_DEAD @p can fall through sched_ext_dead() in that window. sched_ext_dead() runs ops.exit_task() on the sched @p was attached to, not on the sched whose init just completed, so the new allocation leaks. Reuse the DEAD signal set by sched_ext_dead(). After __scx_init_task() returns, take task_rq_lock(p) and check for DEAD; on hit, call scx_sub_init_cancel_task() against the sub sched the init ran for and drop @p; on miss, proceed as before. Reported-by: zhidao su <suzhidao@xiaomi.com> Link: https://lore.kernel.org/all/20260429133155.3825247-1-suzhidao@xiaomi.com/ Signed-off-by: Tejun Heo <tj@kernel.org> Reviewed-by: Andrea Righi <arighi@nvidia.com>
1 parent c941d73 commit cd6aab7

1 file changed

Lines changed: 31 additions & 1 deletion

File tree

kernel/sched/ext.c

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5777,6 +5777,21 @@ static void scx_sub_disable(struct scx_sched *sch)
57775777
}
57785778

57795779
rq = task_rq_lock(p, &rf);
5780+
5781+
if (scx_get_task_state(p) == SCX_TASK_DEAD) {
5782+
/*
5783+
* sched_ext_dead() raced us between __scx_init_task()
5784+
* and this rq lock and ran exit_task() on @sch (the
5785+
* sched @p was on at that point), not on $parent.
5786+
* $parent's just-completed init is owed an exit_task()
5787+
* and we issue it here.
5788+
*/
5789+
scx_sub_init_cancel_task(parent, p);
5790+
task_rq_unlock(rq, p, &rf);
5791+
put_task_struct(p);
5792+
continue;
5793+
}
5794+
57805795
scoped_guard (sched_change, p, DEQUEUE_SAVE | DEQUEUE_MOVE) {
57815796
/*
57825797
* $p is initialized for $parent and still attached to
@@ -5791,8 +5806,8 @@ static void scx_sub_disable(struct scx_sched *sch)
57915806
scx_set_task_state(p, SCX_TASK_READY);
57925807
scx_enable_task(parent, p);
57935808
}
5794-
task_rq_unlock(rq, p, &rf);
57955809

5810+
task_rq_unlock(rq, p, &rf);
57965811
put_task_struct(p);
57975812
}
57985813
scx_task_iter_stop(&sti);
@@ -7212,6 +7227,21 @@ static void scx_sub_enable_workfn(struct kthread_work *work)
72127227
goto abort;
72137228

72147229
rq = task_rq_lock(p, &rf);
7230+
7231+
if (scx_get_task_state(p) == SCX_TASK_DEAD) {
7232+
/*
7233+
* sched_ext_dead() raced us between __scx_init_task()
7234+
* and this rq lock and ran exit_task() on $parent (the
7235+
* sched @p was on at that point), not on @sch. @sch's
7236+
* just-completed init is owed an exit_task() and we
7237+
* issue it here.
7238+
*/
7239+
scx_sub_init_cancel_task(sch, p);
7240+
task_rq_unlock(rq, p, &rf);
7241+
put_task_struct(p);
7242+
continue;
7243+
}
7244+
72157245
p->scx.flags |= SCX_TASK_SUB_INIT;
72167246
task_rq_unlock(rq, p, &rf);
72177247

0 commit comments

Comments
 (0)