* [PATCH] sched_ext: make DSQ iterator stay drained after NULL
@ 2026-11-10 12:51 Kang Chen
2026-11-10 19:37 ` Tejun Heo
0 siblings, 1 reply; 2+ messages in thread
From: Kang Chen @ 2026-11-10 12:51 UTC (permalink / raw)
To: Tejun Heo, David Vernet, Andrea Righi, Changwoo Min
Cc: sched-ext, linux-kernel, bpf
nldsq_cursor_next_task() unlinks the iteration cursor when it reaches the
end of the DSQ. A later call sees list_empty(&cursor->node), starts
from the DSQ head again, and returns the first task of the same
iteration.
The verifier relies on the iterator contract that once next() returns
NULL it keeps returning NULL: process_iter_next_call() marks the
iterator DRAINED and treats the result of later next() calls as the
constant zero. A restarted DSQ iteration therefore hands the BPF
program a task pointer while the verifier believes R0 == 0.
Remember the drained state in the cursor flags and return NULL on every
later next() call. The cursor has spare flag bits and the BPF-visible
iterator layout is unchanged.
Fixes: 650ba21b131e ("sched_ext: Implement DSQ iterator")
Signed-off-by: Kang Chen <k.chen@smail.nju.edu.cn>
---
kernel/sched/ext/ext.c | 17 +++++++++++++++--
1 file changed, 15 insertions(+), 2 deletions(-)
diff --git a/kernel/sched/ext/ext.c b/kernel/sched/ext/ext.c
index 9bae826d69f9..03e0fbf17011 100644
--- a/kernel/sched/ext/ext.c
+++ b/kernel/sched/ext/ext.c
@@ -555,12 +555,14 @@ enum scx_dsq_iter_flags {
/* iterate in the reverse dispatch order */
SCX_DSQ_ITER_REV = 1U << 16,
+ __SCX_DSQ_ITER_DRAINED = 1U << 28,
__SCX_DSQ_ITER_HAS_REENQ = 1U << 29,
__SCX_DSQ_ITER_HAS_SLICE = 1U << 30,
__SCX_DSQ_ITER_HAS_VTIME = 1U << 31,
__SCX_DSQ_ITER_USER_FLAGS = SCX_DSQ_ITER_REV,
__SCX_DSQ_ITER_ALL_FLAGS = __SCX_DSQ_ITER_USER_FLAGS |
+ __SCX_DSQ_ITER_DRAINED |
__SCX_DSQ_ITER_HAS_REENQ |
__SCX_DSQ_ITER_HAS_SLICE |
__SCX_DSQ_ITER_HAS_VTIME,
@@ -10615,13 +10617,24 @@ __bpf_kfunc int bpf_iter_scx_dsq_new(struct bpf_iter_scx_dsq *it, u64 dsq_id,
__bpf_kfunc struct task_struct *bpf_iter_scx_dsq_next(struct bpf_iter_scx_dsq *it)
{
struct bpf_iter_scx_dsq_kern *kit = (void *)it;
+ struct task_struct *p;
- if (!kit->dsq)
+ if (!kit->dsq || (kit->cursor.flags & __SCX_DSQ_ITER_DRAINED))
return NULL;
guard(raw_spinlock_irqsave)(&kit->dsq->lock);
- return nldsq_cursor_next_task(&kit->cursor, kit->dsq);
+ p = nldsq_cursor_next_task(&kit->cursor, kit->dsq);
+ /*
+ * nldsq_cursor_next_task() unlinks the cursor and starts from the DSQ
+ * head when it is called again. The verifier relies on an iterator
+ * which returned NULL to keep returning NULL (see
+ * process_iter_next_call()), so remember the drained state.
+ */
+ if (!p)
+ kit->cursor.flags |= __SCX_DSQ_ITER_DRAINED;
+
+ return p;
}
/**
--
2.34.1
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-11-10 19:37 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-11-10 12:51 [PATCH] sched_ext: make DSQ iterator stay drained after NULL Kang Chen
2026-11-10 19:37 ` Tejun Heo
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®