Skip to content

Commit 5ddd444

Browse files
htejungregkh
authored andcommitted
sched_ext: Fix bypass depth leak on scx_enable() failure
commit 9f76963 upstream. scx_enable() calls scx_bypass(true) to initialize in bypass mode and then scx_bypass(false) on success to exit. If scx_enable() fails during task initialization - e.g. scx_cgroup_init() or scx_init_task() returns an error - it jumps to err_disable while bypass is still active. scx_disable_workfn() then calls scx_bypass(true/false) for its own bypass, leaving the bypass depth at 1 instead of 0. This causes the system to remain permanently in bypass mode after a failed scx_enable(). Failures after task initialization is complete - e.g. scx_tryset_enable_state() at the end - already call scx_bypass(false) before reaching the error path and are not affected. This only affects a subset of failure modes. Fix it by tracking whether scx_enable() called scx_bypass(true) in a bool and having scx_disable_workfn() call an extra scx_bypass(false) to clear it. This is a temporary measure as the bypass depth will be moved into the sched instance, which will make this tracking unnecessary. Fixes: 8c2090c ("sched_ext: Initialize in bypass mode") Cc: stable@vger.kernel.org # v6.12+ Reported-by: Chris Mason <clm@meta.com> Reviewed-by: Emil Tsalapatis <emil@etsalapatis.com> Link: https://lore.kernel.org/stable/286e6f7787a81239e1ce2989b52391ce%40kernel.org Signed-off-by: Tejun Heo <tj@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent ff67270 commit 5ddd444

1 file changed

Lines changed: 14 additions & 0 deletions

File tree

kernel/sched/ext.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,13 @@ static bool scx_init_task_enabled;
4040
static bool scx_switching_all;
4141
DEFINE_STATIC_KEY_FALSE(__scx_switched_all);
4242

43+
/*
44+
* Tracks whether scx_enable() called scx_bypass(true). Used to balance bypass
45+
* depth on enable failure. Will be removed when bypass depth is moved into the
46+
* sched instance.
47+
*/
48+
static bool scx_bypassed_for_enable;
49+
4350
static atomic_long_t scx_nr_rejected = ATOMIC_LONG_INIT(0);
4451
static atomic_long_t scx_hotplug_seq = ATOMIC_LONG_INIT(0);
4552

@@ -4051,6 +4058,11 @@ static void scx_disable_workfn(struct kthread_work *work)
40514058
scx_dsp_max_batch = 0;
40524059
free_kick_pseqs();
40534060

4061+
if (scx_bypassed_for_enable) {
4062+
scx_bypassed_for_enable = false;
4063+
scx_bypass(false);
4064+
}
4065+
40544066
mutex_unlock(&scx_enable_mutex);
40554067

40564068
WARN_ON_ONCE(scx_set_enable_state(SCX_DISABLED) != SCX_DISABLING);
@@ -4676,6 +4688,7 @@ static int scx_enable(struct sched_ext_ops *ops, struct bpf_link *link)
46764688
* Init in bypass mode to guarantee forward progress.
46774689
*/
46784690
scx_bypass(true);
4691+
scx_bypassed_for_enable = true;
46794692

46804693
for (i = SCX_OPI_NORMAL_BEGIN; i < SCX_OPI_NORMAL_END; i++)
46814694
if (((void (**)(void))ops)[i])
@@ -4780,6 +4793,7 @@ static int scx_enable(struct sched_ext_ops *ops, struct bpf_link *link)
47804793
scx_task_iter_stop(&sti);
47814794
percpu_up_write(&scx_fork_rwsem);
47824795

4796+
scx_bypassed_for_enable = false;
47834797
scx_bypass(false);
47844798

47854799
if (!scx_tryset_enable_state(SCX_ENABLED, SCX_ENABLING)) {

0 commit comments

Comments
 (0)