[PATCH 03/15] sched: Add helper to block retained proxy donors
Andrea Righi <[email protected]> Tue, 28 Jul 2026 17:43:21 +0200
| Newsgroups | dev.linux.lists.sched-ext,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
Scheduler ownership changes may need to turn a mutex-blocked task retained on the runqueue for proxy execution back into a normally blocked task. Add sched_proxy_block_task() to perform that transition while holding p->pi_lock and the task's runqueue lock. Reset an active donor to the physical current task before blocking it. If DELAY_DEQUEUE keeps a FAIR donor queued, the immediately following sched_change_begin() completes the dequeue through switching_from_fair() before recording its queued state. This is a preparatory change to support proxy execution with sched_ext. Acked-by: John Stultz <[email protected]> Signed-off-by: Andrea Righi <[email protected]> --- kernel/sched/core.c | 28 ++++++++++++++++++++++++++++ kernel/sched/sched.h | 6 ++++++ 2 files changed, 34 insertions(+) diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 96b8b01d43101..2cc6c9d16200c 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -6764,6 +6764,34 @@ static void proxy_deactivate(struct rq *rq, struct task_struct *donor) block_task(rq, donor, state); } +/* + * Remove a retained proxy donor before changing its scheduler ownership. + * The caller holds p->pi_lock, so p cannot wake and migrate if block_task() + * drops it from the runqueue. If DELAY_DEQUEUE keeps a blocked fair task + * queued, switching_from_fair() completes the dequeue in the immediately + * following sched_change_begin(). + */ +void sched_proxy_block_task(struct rq *rq, struct task_struct *p) +{ + unsigned long state = READ_ONCE(p->__state); + + lockdep_assert_held(&p->pi_lock); + lockdep_assert_rq_held(rq); + + if (!p->is_blocked || !task_on_rq_queued(p)) + return; + if (WARN_ON_ONCE(state == TASK_RUNNING)) + return; + + if (task_current_donor(rq, p)) + proxy_reset_donor(rq); + + if (!p->se.sched_delayed) + block_task(rq, p, state); + + WARN_ON_ONCE(task_on_rq_queued(p) && !p->se.sched_delayed); +} + static inline void proxy_release_rq_lock(struct rq *rq, struct rq_flags *rf) __releases(__rq_lockp(rq)) { diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index c0cb879d75f03..6119bfd2de60d 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -2476,6 +2476,12 @@ static inline bool task_is_blocked(struct task_struct *p) return !!p->blocked_on; } +#ifdef CONFIG_SCHED_PROXY_EXEC +void sched_proxy_block_task(struct rq *rq, struct task_struct *p); +#else +static inline void sched_proxy_block_task(struct rq *rq, struct task_struct *p) {} +#endif + static inline int task_on_cpu(struct rq *rq, struct task_struct *p) { return p->on_cpu; -- 2.55.0