diff --git a/kernel/sched/ext/ext.c b/kernel/sched/ext/ext.c index aa00b7537182..6fec09fd0970 100644 --- a/kernel/sched/ext/ext.c +++ b/kernel/sched/ext/ext.c @@ -2454,7 +2454,11 @@ static void ops_dequeue(struct rq *rq, struct task_struct *p, u64 deq_flags) struct scx_sched *sch = scx_task_sched(p); unsigned long opss; - /* dequeue is always temporary, don't reset runnable_at */ + /* + * Don't reset runnable_at. If @p is waiting, the wait continues across + * temporary dequeues, e.g. for a migration or an attribute change. + * scx_disable_task() ends it if @p leaves its scheduler. + */ clr_task_runnable(p, false); retry: @@ -4554,6 +4558,14 @@ static void scx_disable_task(struct scx_sched *sch, struct task_struct *p) scx_set_task_slice(p, 0); p->scx.reenq_cnt = 0; + /* + * If @p is runnable but not running, its wait started at runnable_at, + * which ops_dequeue() didn't reset. Leaving @sch ends the wait. Reset + * runnable_at the next time @p is enqueued on SCX, so that the watchdog + * doesn't count the time @p spends elsewhere. + */ + p->scx.flags |= SCX_TASK_RESET_RUNNABLE_AT; + /* * Verify the task is not in BPF scheduler's custody. If flag * transitions are consistent, the flag should always be clear