* [PATCH 0/2] sched_ext: sync compat.bpf.h peek/reenqueue fixes from sched-ext/scx
@ 2026-08-17 14:31 Changwoo Min
2026-08-17 14:31 ` [PATCH 1/2] compat.bpf.h: Gate scx_bpf_dsq_peek kfunc behind kernel version 7.1.0 Changwoo Min
2026-08-17 14:31 ` [PATCH 2/2] compat.bpf.h: add scx_bpf_reenqueue_local_from_anywhere() compat helper Changwoo Min
0 siblings, 2 replies; 5+ messages in thread
From: Changwoo Min @ 2026-08-17 14:31 UTC (permalink / raw)
To: tj, void, arighi, changwoo; +Cc: gavinguo, kernel-dev, sched-ext, linux-kernel
These two fixes landed first in the sched-ext/scx tree [1], which carries
the reference scx/compat.bpf.h. This series syncs them into the kernel
tree's tools/sched_ext/include/scx/compat.bpf.h.
Patch 1 gates the lockless scx_bpf_dsq_peek() behind kernel >= 7.1.0,
where its stale task-pointer bug is fixed (2f2ea7709266, 71d7847cad44);
older kernels fall back to bpf_iter_scx_dsq.
Patch 2 adds scx_bpf_reenqueue_local_from_anywhere() and prefers the
generic scx_bpf_dsq_reenq() kfunc, giving arbitrary-context callers a
supported entry point (-ENOTSUP when unavailable).
[1] https://github.com/sched-ext/scx
Changwoo Min (1):
compat.bpf.h: add scx_bpf_reenqueue_local_from_anywhere() compat
helper
Gavin Guo (1):
compat.bpf.h: Gate scx_bpf_dsq_peek kfunc behind kernel version 7.1.0
tools/sched_ext/include/scx/compat.bpf.h | 48 ++++++++++++++++++------
1 file changed, 37 insertions(+), 11 deletions(-)
base-commit: e5a0a3d6b05a62a2921698a60f2c84ea3da97d51
--
2.55.0
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 1/2] compat.bpf.h: Gate scx_bpf_dsq_peek kfunc behind kernel version 7.1.0
2026-08-17 14:31 [PATCH 0/2] sched_ext: sync compat.bpf.h peek/reenqueue fixes from sched-ext/scx Changwoo Min
@ 2026-08-17 14:31 ` Changwoo Min
2026-08-17 17:41 ` Tejun Heo
2026-08-17 14:31 ` [PATCH 2/2] compat.bpf.h: add scx_bpf_reenqueue_local_from_anywhere() compat helper Changwoo Min
1 sibling, 1 reply; 5+ messages in thread
From: Changwoo Min @ 2026-08-17 14:31 UTC (permalink / raw)
To: tj, void, arighi, changwoo; +Cc: gavinguo, kernel-dev, sched-ext, linux-kernel
From: Gavin Guo <gavinguo@igalia.com>
__COMPAT_scx_bpf_dsq_peek() selects the lockless kfunc whenever the
symbol resolves in the kernel BTF. However, its lockless implementation
could return a stale task_struct pointer. The stale pointer issues are
resolved only after v7.1 kernel with the following patches:
commit 2f2ea7709266 ("sched_ext: Use dsq->first_task instead of list_empty() in dispatch_enqueue() FIFO-tail")
commit 71d7847cad44 ("sched_ext: Fix scx_bpf_dsq_peek() with FIFO DSQs")
Require bpf_ksym_exists(scx_bpf_dsq_peek) AND LINUX_KERNEL_VERSION >=
KERNEL_VERSION(7, 1, 0) before calling the kfunc to mitigate the issue;
otherwise fall through to the existing bpf_iter_scx_dsq path instead.
See also the lavd patch, working around the bug by avoiding calling
the kfunc when unnecessary and having more context explanation:
ac863374ce4f ("scx_lavd: Gate dsq_peek_task_load behind no-fast-lb")
Signed-off-by: Gavin Guo <gavinguo@igalia.com>
Signed-off-by: Changwoo Min <changwoo@igalia.com>
---
tools/sched_ext/include/scx/compat.bpf.h | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/tools/sched_ext/include/scx/compat.bpf.h b/tools/sched_ext/include/scx/compat.bpf.h
index 3ab642f92c8a..03976f5851d9 100644
--- a/tools/sched_ext/include/scx/compat.bpf.h
+++ b/tools/sched_ext/include/scx/compat.bpf.h
@@ -92,15 +92,20 @@ int bpf_cpumask_populate(struct bpf_cpumask *dst, void *src, size_t src__sz) __k
/*
* v6.19: Introduce lockless peek API for user DSQs.
+ * v7.1: Resolve the stale pointer issue of the lockless peek API.
+ *
+ * The kfunc exists on earlier kernels but its lockless implementation could
+ * return stale task pointers. Require kernel version >= 7.1.0 before calling
+ * it; otherwise fall through to the bpf_iter_scx_dsq fallback below.
*
- * Preserve the following macro until v6.21.
*/
static inline struct task_struct *__COMPAT_scx_bpf_dsq_peek(u64 dsq_id)
{
struct task_struct *p = NULL;
struct bpf_iter_scx_dsq it;
- if (bpf_ksym_exists(scx_bpf_dsq_peek))
+ if (bpf_ksym_exists(scx_bpf_dsq_peek) &&
+ LINUX_KERNEL_VERSION >= KERNEL_VERSION(7, 1, 0))
return scx_bpf_dsq_peek(dsq_id);
if (!bpf_iter_scx_dsq_new(&it, dsq_id, 0))
p = bpf_iter_scx_dsq_next(&it);
--
2.55.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 2/2] compat.bpf.h: add scx_bpf_reenqueue_local_from_anywhere() compat helper
2026-08-17 14:31 [PATCH 0/2] sched_ext: sync compat.bpf.h peek/reenqueue fixes from sched-ext/scx Changwoo Min
2026-08-17 14:31 ` [PATCH 1/2] compat.bpf.h: Gate scx_bpf_dsq_peek kfunc behind kernel version 7.1.0 Changwoo Min
@ 2026-08-17 14:31 ` Changwoo Min
2026-08-17 17:41 ` Tejun Heo
1 sibling, 1 reply; 5+ messages in thread
From: Changwoo Min @ 2026-08-17 14:31 UTC (permalink / raw)
To: tj, void, arighi, changwoo; +Cc: gavinguo, kernel-dev, sched-ext, linux-kernel
scx_bpf_reenqueue_local()'s generic compat wrapper inlines a v1 fallback
that is only callable from ops.cpu_release, and veristat rejects it on
kernels without v2. Callers draining a local DSQ from an arbitrary
context (e.g. a tracepoint) must gate on a call-from-anywhere kfunc
directly.
Add scx_bpf_reenqueue_local_from_anywhere() to compat.bpf.h to
encapsulate that: call a call-from-anywhere kfunc when present and return
0, else return -ENOTSUP so the caller knows the drain did not run. Two
kfuncs qualify -- the v7.1 generic scx_bpf_dsq_reenq(), which will
eventually deprecate scx_bpf_reenqueue_local(), and the v6.19 v2
reenqueue-local variant. Prefer the generic one; v1 cannot be called from
anywhere, so it maps to -ENOTSUP. scx_bpf_reenqueue_local() itself grows
the same generic-first preference, and the scx_bpf_dsq_reenq___compat
declaration and __COMPAT_has_generic_reenq() helper move above the v6.19
block so both wrappers can use them.
Test each ksym in its own branch: ORing two bpf_ksym_exists() checks
folds into a bitwise OR of the two weak ksym addresses, which the
verifier rejects.
No functional change intended.
Suggested-by: Andrea Righi <arighi@nvidia.com>
Signed-off-by: Changwoo Min <changwoo@igalia.com>
Signed-off-by: Tejun Heo <tj@kernel.org>
---
tools/sched_ext/include/scx/compat.bpf.h | 39 ++++++++++++++++++------
1 file changed, 30 insertions(+), 9 deletions(-)
diff --git a/tools/sched_ext/include/scx/compat.bpf.h b/tools/sched_ext/include/scx/compat.bpf.h
index 03976f5851d9..55f118e40545 100644
--- a/tools/sched_ext/include/scx/compat.bpf.h
+++ b/tools/sched_ext/include/scx/compat.bpf.h
@@ -383,6 +383,17 @@ static inline void scx_bpf_task_set_dsq_vtime(struct task_struct *p, u64 vtime)
p->scx.dsq_vtime = vtime;
}
+/*
+ * v7.1: New scx_bpf_dsq_reenq() that allows re-enqueues on more DSQs. This
+ * will eventually deprecate scx_bpf_reenqueue_local().
+ */
+void scx_bpf_dsq_reenq___compat(u64 dsq_id, u64 reenq_flags) __ksym __weak;
+
+static inline bool __COMPAT_has_generic_reenq(void)
+{
+ return bpf_ksym_exists(scx_bpf_dsq_reenq___compat);
+}
+
/*
* v6.19: The new void variant can be called from anywhere while the older v1
* variant can only be called from ops.cpu_release(). The double ___ prefixes on
@@ -400,21 +411,31 @@ static inline bool __COMPAT_scx_bpf_reenqueue_local_from_anywhere(void)
static inline void scx_bpf_reenqueue_local(void)
{
- if (__COMPAT_scx_bpf_reenqueue_local_from_anywhere())
+ if (__COMPAT_has_generic_reenq())
+ scx_bpf_dsq_reenq___compat(SCX_DSQ_LOCAL, 0);
+ else if (__COMPAT_scx_bpf_reenqueue_local_from_anywhere())
scx_bpf_reenqueue_local___v2___compat();
else
scx_bpf_reenqueue_local___v1();
}
-/*
- * v7.1: New scx_bpf_dsq_reenq() that allows re-enqueues on more DSQs. This
- * will eventually deprecate scx_bpf_reenqueue_local().
- */
-void scx_bpf_dsq_reenq___compat(u64 dsq_id, u64 reenq_flags) __ksym __weak;
-
-static inline bool __COMPAT_has_generic_reenq(void)
+static inline int scx_bpf_reenqueue_local_from_anywhere(void)
{
- return bpf_ksym_exists(scx_bpf_dsq_reenq___compat);
+ /*
+ * The generic reenq kfunc and the v2 reenqueue-local variant can both be
+ * called from anywhere; v1 cannot. Test each ksym in its own branch with a
+ * distinct call: combining them with || would fold into a bitwise OR of the
+ * two ksym addresses, which the verifier rejects.
+ */
+ if (__COMPAT_has_generic_reenq()) {
+ scx_bpf_dsq_reenq___compat(SCX_DSQ_LOCAL, 0);
+ return 0;
+ }
+ if (__COMPAT_scx_bpf_reenqueue_local_from_anywhere()) {
+ scx_bpf_reenqueue_local___v2___compat();
+ return 0;
+ }
+ return -ENOTSUP;
}
static inline void scx_bpf_dsq_reenq(u64 dsq_id, u64 reenq_flags)
--
2.55.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH 1/2] compat.bpf.h: Gate scx_bpf_dsq_peek kfunc behind kernel version 7.1.0
2026-08-17 14:31 ` [PATCH 1/2] compat.bpf.h: Gate scx_bpf_dsq_peek kfunc behind kernel version 7.1.0 Changwoo Min
@ 2026-08-17 17:41 ` Tejun Heo
0 siblings, 0 replies; 5+ messages in thread
From: Tejun Heo @ 2026-08-17 17:41 UTC (permalink / raw)
To: Changwoo Min, Gavin Guo
Cc: David Vernet, Andrea Righi, kernel-dev, sched-ext, linux-kernel
Hello,
On Mon, Aug 17, 2026 at 11:31:25PM +0900, Changwoo Min wrote:
> __COMPAT_scx_bpf_dsq_peek() selects the lockless kfunc whenever the
> symbol resolves in the kernel BTF. However, its lockless implementation
> could return a stale task_struct pointer. The stale pointer issues are
> resolved only after v7.1 kernel with the following patches:
>
> commit 2f2ea7709266 ("sched_ext: Use dsq->first_task instead of list_empty() in dispatch_enqueue() FIFO-tail")
> commit 71d7847cad44 ("sched_ext: Fix scx_bpf_dsq_peek() with FIFO DSQs")
71d7847cad44 shipped in v6.19 together with the peek API itself, so every
mainline release that has the kfunc already has it. Only 2f2ea7709266 is
new in v7.1, and what it fixes on v6.19/v7.0 is scx_bpf_dsq_peek()
spuriously returning NULL on a non-empty FIFO DSQ, not stale pointers.
The gate itself looks fine but can you update the description and the
comment so that they describe what the gate is actually avoiding?
> + * The kfunc exists on earlier kernels but its lockless implementation could
> + * return stale task pointers. Require kernel version >= 7.1.0 before calling
> + * it; otherwise fall through to the bpf_iter_scx_dsq fallback below.
> + *
> */
Also, the edit leaves a dangling " *" line before the closing "*/".
Thanks.
--
tejun
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 2/2] compat.bpf.h: add scx_bpf_reenqueue_local_from_anywhere() compat helper
2026-08-17 14:31 ` [PATCH 2/2] compat.bpf.h: add scx_bpf_reenqueue_local_from_anywhere() compat helper Changwoo Min
@ 2026-08-17 17:41 ` Tejun Heo
0 siblings, 0 replies; 5+ messages in thread
From: Tejun Heo @ 2026-08-17 17:41 UTC (permalink / raw)
To: Changwoo Min
Cc: David Vernet, Andrea Righi, Gavin Guo, kernel-dev, sched-ext,
linux-kernel
Hello, Changwoo.
On Mon, Aug 17, 2026 at 11:31:26PM +0900, Changwoo Min wrote:
> + if (__COMPAT_scx_bpf_reenqueue_local_from_anywhere()) {
> + scx_bpf_reenqueue_local___v2___compat();
> + return 0;
> + }
> + return -ENOTSUP;
ENOTSUP is glibc-only. The BPF side picks up errno constants through
asm-generic/errno.h (see common.bpf.h), which only defines EOPNOTSUPP,
and as static inline bodies are checked in every TU whether called or
not, this breaks the BPF build for every scheduler. Use -EOPNOTSUPP like
__COMPAT_bpf_cpumask_populate() in the same file and update the
description accordingly. The pending scx-side PR needs the same fix.
The rest of the patch looks good to me.
Thanks.
--
tejun
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-08-17 17:41 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-17 14:31 [PATCH 0/2] sched_ext: sync compat.bpf.h peek/reenqueue fixes from sched-ext/scx Changwoo Min
2026-08-17 14:31 ` [PATCH 1/2] compat.bpf.h: Gate scx_bpf_dsq_peek kfunc behind kernel version 7.1.0 Changwoo Min
2026-08-17 17:41 ` Tejun Heo
2026-08-17 14:31 ` [PATCH 2/2] compat.bpf.h: add scx_bpf_reenqueue_local_from_anywhere() compat helper Changwoo Min
2026-08-17 17:41 ` Tejun Heo
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox