Re: [RFC PATCH sched_ext/for-7.2 0/10] sched: Make proxy execution compatible with sched_ext

From: Tejun Heo

Date: Sun May 10 2026 - 15:41:46 EST


Hello,

I'll think more on enabling proxy execution as-is for sched_ext. Reponse on
scx_bpf_dsq_move():

On Sun, May 10, 2026 at 05:06:41PM +0200, Andrea Righi wrote:
...
> Let's say we expose blocked_on (and a kfunc returning the mutex owner) via
> tagged ops.quiescent/runnable(). The BPF scheduler now wants to boost the owner.
> What's the actual way to do so? Some mechanisms that we have right now:
> - slice extension: scx_bpf_task_set_slice() works in place, but it affects
> only a running owner,
> - dsq_vtime: scx_bpf_task_set_dsq_vtime() updates the value, but for a task
> already enqueued in a PRIQ DSQ the position in the rbtree doesn't move, so
> this doesn't actually boost an already-queued owner.
> - DSQ move: scx_bpf_dsq_move() requires an iterator and the task to have been
> queued before iteration started. We don't have a kfunc today that takes a
> task pointer and atomically yanks it from wherever it is to a higher-priority
> DSQ. We also have no API exposing which DSQ a task is currently sitting in.

Assuming ->blocked_on() is triggered without rq lock held (if not, we just
need to tell scx_bpf_dsq_move() that it can do lock dancing in this context
too), we should already be able to move the task directly:

p->scx.dsq->id should already be accessible through BPF_CORE_READ(). Maybe
we can make it a bit nicer.

scx_bpf_dsq_move() doesn't actually need the task to come from iteration.
It's a bit odd but we're overloading the iterator for two purposes -
iteration and transaction scope definition. If a task is dequeued and
reenqueued after iteration is opened, scx_bpf_dsq_move() ignores the move as
the visit is considered stale. scx_bpf_dsq_move() only depends on this part.
The following is an excerpt from the function comment:

* For the transfer to be successful, @p must still be on the DSQ and have been
* queued before the DSQ iteration started. This function doesn't care whether
* @p was obtained from the DSQ iteration. @p just has to be on the DSQ and have
* been queued before the iteration started.

So, for an example, ->blocked_on() can do:

void my_sched_blocked_on(struct task_struct *p, struct task_struct *blocker)
{
u64 dsq_id = BPF_CORE_READ(p, scx.dsq, id);
struct bpf_iter_scx_dsq it;

if (!bpf_iter_scx_dsq_new(&it, dsq_id, 0)) {
scx_bpf_dsq_move(&it, p, SCX_DSQ_LOCAL_ON | WHATEVER_CPU_WE_PICK,
SCX_ENQ_PREEMPT);
bpf_iter_scx_dsq_destroy(&it);
}
}

This is not the prettiest but the above should do all that's needed and
nothing else. It just looks up the dsq and remembers the insert sequence. No
actual iteration happens. Again, it'd be trivial to add BPF helpers or extra
kfuncs to make this nicer.

Thanks.

--
tejun