[PATCH 1/3] sched_ext: Disallow setting slice to zero via scx_bpf_task_set_slice()
From: Tejun Heo
Date: Fri Mar 06 2026 - 19:28:46 EST
A task's slice can reach zero through natural consumption in update_curr_scx()
as time passes, yielding, and preemption. In all these cases, the task is
about to go through scheduling and off CPU. scx_bpf_task_set_slice() is
currently the only path that can set slice to zero without triggering a
scheduling event.
The upcoming SCX_ENQ_IMMED flag will allow BPF schedulers to dispatch tasks
only when the target CPU can run the task immediately. To determine whether
a CPU is open for new tasks, the core can test whether the current task's
slice is zero.
Close the hole by disallowing scx_bpf_task_set_slice() from setting slice to
zero. To preempt the current task, use scx_bpf_kick_cpu() with SCX_KICK_PREEMPT.
To force slice expiration on the next tick, set it to 1.
Signed-off-by: Tejun Heo <tj@xxxxxxxxxx>
---
kernel/sched/ext.c | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c
index 66af7a83bb1e..8c42405e27fd 100644
--- a/kernel/sched/ext.c
+++ b/kernel/sched/ext.c
@@ -8210,11 +8210,17 @@ __bpf_kfunc_start_defs();
/**
* scx_bpf_task_set_slice - Set task's time slice
* @p: task of interest
- * @slice: time slice to set in nsecs
+ * @slice: non-zero time slice to set in nsecs
* @aux: implicit BPF argument to access bpf_prog_aux hidden from BPF progs
*
* Set @p's time slice to @slice. Returns %true on success, %false if the
* calling scheduler doesn't have authority over @p.
+ *
+ * @slice cannot be zero to ensure that 0 slice reliably indicates that the task
+ * has expired and is soon to go through scheduling. To clear the slice of a
+ * running task and trigger preemption, use scx_bpf_kick_cpu() with
+ * %SCX_KICK_PREEMPT. To force slice expiration on the next tick, use 1 which is
+ * practically guaranteed to expire on the following tick.
*/
__bpf_kfunc bool scx_bpf_task_set_slice(struct task_struct *p, u64 slice,
const struct bpf_prog_aux *aux)
@@ -8226,6 +8232,11 @@ __bpf_kfunc bool scx_bpf_task_set_slice(struct task_struct *p, u64 slice,
if (unlikely(!scx_task_on_sched(sch, p)))
return false;
+ if (unlikely(!slice)) {
+ scx_error(sch, "scx_bpf_task_set_slice() called with 0 slice, use SCX_KICK_PREEMPT instead");
+ return false;
+ }
+
p->scx.slice = slice;
return true;
}
--
2.53.0