Skip to content

Commit 9f76963

Browse files
committed
sched_ext: Fix bypass depth leak on scx_enable() failure
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>
1 parent 12b5cd9 commit 9f76963

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
@@ -41,6 +41,13 @@ static bool scx_init_task_enabled;
4141
static bool scx_switching_all;
4242
DEFINE_STATIC_KEY_FALSE(__scx_switched_all);
4343

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

@@ -4318,6 +4325,11 @@ static void scx_disable_workfn(struct kthread_work *work)
43184325
scx_dsp_max_batch = 0;
43194326
free_kick_syncs();
43204327

4328+
if (scx_bypassed_for_enable) {
4329+
scx_bypassed_for_enable = false;
4330+
scx_bypass(false);
4331+
}
4332+
43214333
mutex_unlock(&scx_enable_mutex);
43224334

43234335
WARN_ON_ONCE(scx_set_enable_state(SCX_DISABLED) != SCX_DISABLING);
@@ -4970,6 +4982,7 @@ static int scx_enable(struct sched_ext_ops *ops, struct bpf_link *link)
49704982
* Init in bypass mode to guarantee forward progress.
49714983
*/
49724984
scx_bypass(true);
4985+
scx_bypassed_for_enable = true;
49734986

49744987
for (i = SCX_OPI_NORMAL_BEGIN; i < SCX_OPI_NORMAL_END; i++)
49754988
if (((void (**)(void))ops)[i])
@@ -5067,6 +5080,7 @@ static int scx_enable(struct sched_ext_ops *ops, struct bpf_link *link)
50675080
scx_task_iter_stop(&sti);
50685081
percpu_up_write(&scx_fork_rwsem);
50695082

5083+
scx_bypassed_for_enable = false;
50705084
scx_bypass(false);
50715085

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

0 commit comments

Comments
 (0)