Re: [PATCH v2 2/2] selftests/sched_ext: Test that ops.dequeue() can iterate the consumed DSQ

From: Tejun Heo

Date: Tue Sep 15 2026 - 15:15:36 EST


Hello, Qiurong.

On Tue, Sep 15, 2026 at 09:03:34PM +0800, Qiurong Fang wrote:
> Add a scheduler whose ops.dequeue() iterates the user DSQ tasks are
> dispatched from with bpf_iter_scx_dsq. The iteration takes the DSQ's raw
> spinlock; on a kernel that runs ops.dequeue() while the consume path
> still holds that lock, the first task consumed self-deadlocks the CPU
> until the scheduler watchdog fires and the test fails with a UEI. On a
> fixed kernel the scheduler runs clean and the test passes.

The watchdog can't recover from this. Both it and the disable path need the
wedged CPU's rq lock. The header comment's "wedges the system" is the
accurate description. Please make the two agree.

> +void BPF_STRUCT_OPS(dequeue_iter_enqueue, struct task_struct *p, u64 enq_flags)
> +{
> + scx_bpf_dsq_insert(p, TEST_DSQ_ID, SCX_SLICE_DFL, enq_flags);
> +}

Without ops.select_cpu(), the default direct-dispatches every wakeup that
finds an idle CPU to the local DSQ, so the poller's own wakeups never reach
TEST_DSQ_ID and the pass condition depends on unrelated traffic. Add a
select_cpu() which returns prev_cpu so that everything flows through the DSQ.

> +void BPF_STRUCT_OPS(dequeue_iter_exit, struct scx_exit_info *ei)
> +{
> + scx_bpf_destroy_dsq(TEST_DSQ_ID);
> +}

Without UEI_RECORD() here, UEI_EXITED() is never true and the failure branch
in run() is dead. Record it, break the poll loop on UEI_EXITED(), and check
for SCX_EXIT_UNREG after destroying the link like the other tests do.

SCX_ERR() already appends the newline.

Thanks.

--
tejun