public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCHSET sched_ext/for-6.19] sched_ext: Misc changes with some prep patches for sub-sched support
@ 2025-10-07  1:51 Tejun Heo
  2025-10-07  1:51 ` [PATCH 1/4] tools/sched_ext: Strip compatibility macros for cgroup and dispatch APIs Tejun Heo
                   ` (5 more replies)
  0 siblings, 6 replies; 26+ messages in thread
From: Tejun Heo @ 2025-10-07  1:51 UTC (permalink / raw)
  To: David Vernet, Andrea Righi, Changwoo Min; +Cc: linux-kernel, sched-ext

Hello,

This patchset contains misc changes and some prep patches for future
sub-scheduler support.

0001-tools-sched_ext-Strip-compatibility-macros-for-cgrou.patch
0002-sched_ext-Add-scx_bpf_task_set_slice-and-scx_bpf_tas.patch
0003-sched_ext-Wrap-kfunc-args-in-struct-to-prepare-for-a.patch
0004-sched_ext-Make-scx_bpf_dsq_insert-return-bool.patch

The patches are based on sched_ext/for-6.19 (7e926e30bfec) +
"sched_ext: Mark scx_bpf_dsq_move_set_[slice|vtime]() with KF_RCU"
(http://lkml.kernel.org/r/aORuaIXJftQDMBIA@slm.duckdns.org).

The following git tree also contains the patchset:

  git://git.kernel.org/pub/scm/linux/kernel/git/tj/sched_ext.git scx-sub-sched-misc-prep2

 kernel/sched/ext.c                       | 147 ++++++++++++++++++-----
 kernel/sched/ext_idle.c                  |  43 ++++++-
 tools/sched_ext/include/scx/common.bpf.h |   9 +-
 tools/sched_ext/include/scx/compat.bpf.h | 199 +++++++++++++++----------------
 tools/sched_ext/scx_flatcg.bpf.c         |  10 +-
 tools/sched_ext/scx_qmap.bpf.c           |  14 +--
 6 files changed, 265 insertions(+), 157 deletions(-)

--
tejun

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH 1/4] tools/sched_ext: Strip compatibility macros for cgroup and dispatch APIs
  2025-10-07  1:51 [PATCHSET sched_ext/for-6.19] sched_ext: Misc changes with some prep patches for sub-sched support Tejun Heo
@ 2025-10-07  1:51 ` Tejun Heo
  2025-10-07  2:42   ` Emil Tsalapatis
                     ` (2 more replies)
  2025-10-07  1:51 ` [PATCH 2/4] sched_ext: Add scx_bpf_task_set_slice() and scx_bpf_task_set_dsq_vtime() Tejun Heo
                   ` (4 subsequent siblings)
  5 siblings, 3 replies; 26+ messages in thread
From: Tejun Heo @ 2025-10-07  1:51 UTC (permalink / raw)
  To: David Vernet, Andrea Righi, Changwoo Min
  Cc: linux-kernel, sched-ext, Tejun Heo

Enough time has passed since the introduction of scx_bpf_task_cgroup() and
the scx_bpf_dispatch* -> scx_bpf_dsq* kfunc renaming. Strip the compatibility
macros.

Signed-off-by: Tejun Heo <tj@kernel.org>
---
 tools/sched_ext/include/scx/compat.bpf.h | 108 +----------------------
 tools/sched_ext/scx_flatcg.bpf.c         |  10 +--
 tools/sched_ext/scx_qmap.bpf.c           |  14 ++-
 3 files changed, 12 insertions(+), 120 deletions(-)

diff --git a/tools/sched_ext/include/scx/compat.bpf.h b/tools/sched_ext/include/scx/compat.bpf.h
index dd9144624dc9..d979f16a3ae2 100644
--- a/tools/sched_ext/include/scx/compat.bpf.h
+++ b/tools/sched_ext/include/scx/compat.bpf.h
@@ -15,121 +15,17 @@
 	__ret;									\
 })
 
-/* v6.12: 819513666966 ("sched_ext: Add cgroup support") */
-#define __COMPAT_scx_bpf_task_cgroup(p)						\
-	(bpf_ksym_exists(scx_bpf_task_cgroup) ?					\
-	 scx_bpf_task_cgroup((p)) : NULL)
-
 /*
- * v6.13: The verb `dispatch` was too overloaded and confusing. kfuncs are
- * renamed to unload the verb.
- *
- * Build error is triggered if old names are used. New binaries work with both
- * new and old names. The compat macros will be removed on v6.15 release.
+ * v6.15: 950ad93df2fc ("bpf: add kfunc for populating cpumask bits")
  *
- * scx_bpf_dispatch_from_dsq() and friends were added during v6.12 by
- * 4c30f5ce4f7a ("sched_ext: Implement scx_bpf_dispatch[_vtime]_from_dsq()").
- * Preserve __COMPAT macros until v6.15.
+ * Compat macro will be dropped on v6.19 release.
  */
-void scx_bpf_dispatch___compat(struct task_struct *p, u64 dsq_id, u64 slice, u64 enq_flags) __ksym __weak;
-void scx_bpf_dispatch_vtime___compat(struct task_struct *p, u64 dsq_id, u64 slice, u64 vtime, u64 enq_flags) __ksym __weak;
-bool scx_bpf_consume___compat(u64 dsq_id) __ksym __weak;
-void scx_bpf_dispatch_from_dsq_set_slice___compat(struct bpf_iter_scx_dsq *it__iter, u64 slice) __ksym __weak;
-void scx_bpf_dispatch_from_dsq_set_vtime___compat(struct bpf_iter_scx_dsq *it__iter, u64 vtime) __ksym __weak;
-bool scx_bpf_dispatch_from_dsq___compat(struct bpf_iter_scx_dsq *it__iter, struct task_struct *p, u64 dsq_id, u64 enq_flags) __ksym __weak;
-bool scx_bpf_dispatch_vtime_from_dsq___compat(struct bpf_iter_scx_dsq *it__iter, struct task_struct *p, u64 dsq_id, u64 enq_flags) __ksym __weak;
 int bpf_cpumask_populate(struct cpumask *dst, void *src, size_t src__sz) __ksym __weak;
 
-#define scx_bpf_dsq_insert(p, dsq_id, slice, enq_flags)				\
-	(bpf_ksym_exists(scx_bpf_dsq_insert) ?					\
-	 scx_bpf_dsq_insert((p), (dsq_id), (slice), (enq_flags)) :		\
-	 scx_bpf_dispatch___compat((p), (dsq_id), (slice), (enq_flags)))
-
-#define scx_bpf_dsq_insert_vtime(p, dsq_id, slice, vtime, enq_flags)		\
-	(bpf_ksym_exists(scx_bpf_dsq_insert_vtime) ?				\
-	 scx_bpf_dsq_insert_vtime((p), (dsq_id), (slice), (vtime), (enq_flags)) : \
-	 scx_bpf_dispatch_vtime___compat((p), (dsq_id), (slice), (vtime), (enq_flags)))
-
-#define scx_bpf_dsq_move_to_local(dsq_id)					\
-	(bpf_ksym_exists(scx_bpf_dsq_move_to_local) ?				\
-	 scx_bpf_dsq_move_to_local((dsq_id)) :					\
-	 scx_bpf_consume___compat((dsq_id)))
-
-#define __COMPAT_scx_bpf_dsq_move_set_slice(it__iter, slice)			\
-	(bpf_ksym_exists(scx_bpf_dsq_move_set_slice) ?				\
-	 scx_bpf_dsq_move_set_slice((it__iter), (slice)) :			\
-	 (bpf_ksym_exists(scx_bpf_dispatch_from_dsq_set_slice___compat) ?	\
-	  scx_bpf_dispatch_from_dsq_set_slice___compat((it__iter), (slice)) :	\
-	  (void)0))
-
-#define __COMPAT_scx_bpf_dsq_move_set_vtime(it__iter, vtime)			\
-	(bpf_ksym_exists(scx_bpf_dsq_move_set_vtime) ?				\
-	 scx_bpf_dsq_move_set_vtime((it__iter), (vtime)) :			\
-	 (bpf_ksym_exists(scx_bpf_dispatch_from_dsq_set_vtime___compat) ?	\
-	  scx_bpf_dispatch_from_dsq_set_vtime___compat((it__iter), (vtime)) :	\
-	  (void) 0))
-
-#define __COMPAT_scx_bpf_dsq_move(it__iter, p, dsq_id, enq_flags)		\
-	(bpf_ksym_exists(scx_bpf_dsq_move) ?					\
-	 scx_bpf_dsq_move((it__iter), (p), (dsq_id), (enq_flags)) :		\
-	 (bpf_ksym_exists(scx_bpf_dispatch_from_dsq___compat) ?			\
-	  scx_bpf_dispatch_from_dsq___compat((it__iter), (p), (dsq_id), (enq_flags)) : \
-	  false))
-
-#define __COMPAT_scx_bpf_dsq_move_vtime(it__iter, p, dsq_id, enq_flags)		\
-	(bpf_ksym_exists(scx_bpf_dsq_move_vtime) ?				\
-	 scx_bpf_dsq_move_vtime((it__iter), (p), (dsq_id), (enq_flags)) :	\
-	 (bpf_ksym_exists(scx_bpf_dispatch_vtime_from_dsq___compat) ?		\
-	  scx_bpf_dispatch_vtime_from_dsq___compat((it__iter), (p), (dsq_id), (enq_flags)) : \
-	  false))
-
 #define __COMPAT_bpf_cpumask_populate(cpumask, src, size__sz)		\
 	(bpf_ksym_exists(bpf_cpumask_populate) ?			\
 	 (bpf_cpumask_populate(cpumask, src, size__sz)) : -EOPNOTSUPP)
 
-#define scx_bpf_dispatch(p, dsq_id, slice, enq_flags)				\
-	_Static_assert(false, "scx_bpf_dispatch() renamed to scx_bpf_dsq_insert()")
-
-#define scx_bpf_dispatch_vtime(p, dsq_id, slice, vtime, enq_flags)		\
-	_Static_assert(false, "scx_bpf_dispatch_vtime() renamed to scx_bpf_dsq_insert_vtime()")
-
-#define scx_bpf_consume(dsq_id) ({						\
-	_Static_assert(false, "scx_bpf_consume() renamed to scx_bpf_dsq_move_to_local()"); \
-	false;									\
-})
-
-#define scx_bpf_dispatch_from_dsq_set_slice(it__iter, slice)		\
-	_Static_assert(false, "scx_bpf_dispatch_from_dsq_set_slice() renamed to scx_bpf_dsq_move_set_slice()")
-
-#define scx_bpf_dispatch_from_dsq_set_vtime(it__iter, vtime)		\
-	_Static_assert(false, "scx_bpf_dispatch_from_dsq_set_vtime() renamed to scx_bpf_dsq_move_set_vtime()")
-
-#define scx_bpf_dispatch_from_dsq(it__iter, p, dsq_id, enq_flags) ({	\
-	_Static_assert(false, "scx_bpf_dispatch_from_dsq() renamed to scx_bpf_dsq_move()"); \
-	false;									\
-})
-
-#define scx_bpf_dispatch_vtime_from_dsq(it__iter, p, dsq_id, enq_flags) ({  \
-	_Static_assert(false, "scx_bpf_dispatch_vtime_from_dsq() renamed to scx_bpf_dsq_move_vtime()"); \
-	false;									\
-})
-
-#define __COMPAT_scx_bpf_dispatch_from_dsq_set_slice(it__iter, slice)		\
-	_Static_assert(false, "__COMPAT_scx_bpf_dispatch_from_dsq_set_slice() renamed to __COMPAT_scx_bpf_dsq_move_set_slice()")
-
-#define __COMPAT_scx_bpf_dispatch_from_dsq_set_vtime(it__iter, vtime)		\
-	_Static_assert(false, "__COMPAT_scx_bpf_dispatch_from_dsq_set_vtime() renamed to __COMPAT_scx_bpf_dsq_move_set_vtime()")
-
-#define __COMPAT_scx_bpf_dispatch_from_dsq(it__iter, p, dsq_id, enq_flags) ({	\
-	_Static_assert(false, "__COMPAT_scx_bpf_dispatch_from_dsq() renamed to __COMPAT_scx_bpf_dsq_move()"); \
-	false;									\
-})
-
-#define __COMPAT_scx_bpf_dispatch_vtime_from_dsq(it__iter, p, dsq_id, enq_flags) ({  \
-	_Static_assert(false, "__COMPAT_scx_bpf_dispatch_vtime_from_dsq() renamed to __COMPAT_scx_bpf_dsq_move_vtime()"); \
-	false;									\
-})
-
 /**
  * __COMPAT_is_enq_cpu_selected - Test if SCX_ENQ_CPU_SELECTED is on
  * in a compatible way. We will preserve this __COMPAT helper until v6.16.
diff --git a/tools/sched_ext/scx_flatcg.bpf.c b/tools/sched_ext/scx_flatcg.bpf.c
index 2c720e3ecad5..43126858b8e4 100644
--- a/tools/sched_ext/scx_flatcg.bpf.c
+++ b/tools/sched_ext/scx_flatcg.bpf.c
@@ -382,7 +382,7 @@ void BPF_STRUCT_OPS(fcg_enqueue, struct task_struct *p, u64 enq_flags)
 		return;
 	}
 
-	cgrp = __COMPAT_scx_bpf_task_cgroup(p);
+	cgrp = scx_bpf_task_cgroup(p);
 	cgc = find_cgrp_ctx(cgrp);
 	if (!cgc)
 		goto out_release;
@@ -508,7 +508,7 @@ void BPF_STRUCT_OPS(fcg_runnable, struct task_struct *p, u64 enq_flags)
 {
 	struct cgroup *cgrp;
 
-	cgrp = __COMPAT_scx_bpf_task_cgroup(p);
+	cgrp = scx_bpf_task_cgroup(p);
 	update_active_weight_sums(cgrp, true);
 	bpf_cgroup_release(cgrp);
 }
@@ -521,7 +521,7 @@ void BPF_STRUCT_OPS(fcg_running, struct task_struct *p)
 	if (fifo_sched)
 		return;
 
-	cgrp = __COMPAT_scx_bpf_task_cgroup(p);
+	cgrp = scx_bpf_task_cgroup(p);
 	cgc = find_cgrp_ctx(cgrp);
 	if (cgc) {
 		/*
@@ -564,7 +564,7 @@ void BPF_STRUCT_OPS(fcg_stopping, struct task_struct *p, bool runnable)
 	if (!taskc->bypassed_at)
 		return;
 
-	cgrp = __COMPAT_scx_bpf_task_cgroup(p);
+	cgrp = scx_bpf_task_cgroup(p);
 	cgc = find_cgrp_ctx(cgrp);
 	if (cgc) {
 		__sync_fetch_and_add(&cgc->cvtime_delta,
@@ -578,7 +578,7 @@ void BPF_STRUCT_OPS(fcg_quiescent, struct task_struct *p, u64 deq_flags)
 {
 	struct cgroup *cgrp;
 
-	cgrp = __COMPAT_scx_bpf_task_cgroup(p);
+	cgrp = scx_bpf_task_cgroup(p);
 	update_active_weight_sums(cgrp, false);
 	bpf_cgroup_release(cgrp);
 }
diff --git a/tools/sched_ext/scx_qmap.bpf.c b/tools/sched_ext/scx_qmap.bpf.c
index 3072b593f898..c67dac78a4c6 100644
--- a/tools/sched_ext/scx_qmap.bpf.c
+++ b/tools/sched_ext/scx_qmap.bpf.c
@@ -320,12 +320,9 @@ static bool dispatch_highpri(bool from_timer)
 
 		if (tctx->highpri) {
 			/* exercise the set_*() and vtime interface too */
-			__COMPAT_scx_bpf_dsq_move_set_slice(
-				BPF_FOR_EACH_ITER, slice_ns * 2);
-			__COMPAT_scx_bpf_dsq_move_set_vtime(
-				BPF_FOR_EACH_ITER, highpri_seq++);
-			__COMPAT_scx_bpf_dsq_move_vtime(
-				BPF_FOR_EACH_ITER, p, HIGHPRI_DSQ, 0);
+			scx_bpf_dsq_move_set_slice(BPF_FOR_EACH_ITER, slice_ns * 2);
+			scx_bpf_dsq_move_set_vtime(BPF_FOR_EACH_ITER, highpri_seq++);
+			scx_bpf_dsq_move_vtime(BPF_FOR_EACH_ITER, p, HIGHPRI_DSQ, 0);
 		}
 	}
 
@@ -342,9 +339,8 @@ static bool dispatch_highpri(bool from_timer)
 		else
 			cpu = scx_bpf_pick_any_cpu(p->cpus_ptr, 0);
 
-		if (__COMPAT_scx_bpf_dsq_move(BPF_FOR_EACH_ITER, p,
-					      SCX_DSQ_LOCAL_ON | cpu,
-					      SCX_ENQ_PREEMPT)) {
+		if (scx_bpf_dsq_move(BPF_FOR_EACH_ITER, p, SCX_DSQ_LOCAL_ON | cpu,
+				     SCX_ENQ_PREEMPT)) {
 			if (cpu == this_cpu) {
 				dispatched = true;
 				__sync_fetch_and_add(&nr_expedited_local, 1);
-- 
2.51.0


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH 2/4] sched_ext: Add scx_bpf_task_set_slice() and scx_bpf_task_set_dsq_vtime()
  2025-10-07  1:51 [PATCHSET sched_ext/for-6.19] sched_ext: Misc changes with some prep patches for sub-sched support Tejun Heo
  2025-10-07  1:51 ` [PATCH 1/4] tools/sched_ext: Strip compatibility macros for cgroup and dispatch APIs Tejun Heo
@ 2025-10-07  1:51 ` Tejun Heo
  2025-10-07  2:56   ` Emil Tsalapatis
                     ` (2 more replies)
  2025-10-07  1:51 ` [PATCH 3/4] sched_ext: Wrap kfunc args in struct to prepare for aux__prog Tejun Heo
                   ` (3 subsequent siblings)
  5 siblings, 3 replies; 26+ messages in thread
From: Tejun Heo @ 2025-10-07  1:51 UTC (permalink / raw)
  To: David Vernet, Andrea Righi, Changwoo Min
  Cc: linux-kernel, sched-ext, Tejun Heo

With the planned hierarchical scheduler support, sub-schedulers will need to
be verified for authority before being allowed to modify task->scx.slice and
task->scx.dsq_vtime. Add scx_bpf_task_set_slice() and
scx_bpf_task_set_dsq_vtime() which will perform the necessary permission
checks.

Root schedulers can still directly write to these fields, so this doesn't
affect existing schedulers.

Signed-off-by: Tejun Heo <tj@kernel.org>
---
 kernel/sched/ext.c                       | 30 ++++++++++++++++++++++++
 tools/sched_ext/include/scx/common.bpf.h |  2 ++
 2 files changed, 32 insertions(+)

diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c
index fc353b8d69f7..6d76efaaa9b2 100644
--- a/kernel/sched/ext.c
+++ b/kernel/sched/ext.c
@@ -5833,6 +5833,34 @@ static const struct btf_kfunc_id_set scx_kfunc_set_unlocked = {
 
 __bpf_kfunc_start_defs();
 
+/**
+ * scx_bpf_task_set_slice - Set task's time slice
+ * @p: task of interest
+ * @slice: time slice to set in nsecs
+ *
+ * Set @p's time slice to @slice. Returns %true on success, %false if the
+ * calling scheduler doesn't have authority over @p.
+ */
+__bpf_kfunc bool scx_bpf_task_set_slice(struct task_struct *p, u64 slice)
+{
+	p->scx.slice = slice;
+	return true;
+}
+
+/**
+ * scx_bpf_task_set_dsq_vtime - Set task's virtual time for DSQ ordering
+ * @p: task of interest
+ * @vtime: virtual time to set
+ *
+ * Set @p's virtual time to @vtime. Returns %true on success, %false if the
+ * calling scheduler doesn't have authority over @p.
+ */
+__bpf_kfunc bool scx_bpf_task_set_dsq_vtime(struct task_struct *p, u64 vtime)
+{
+	p->scx.dsq_vtime = vtime;
+	return true;
+}
+
 static void scx_kick_cpu(struct scx_sched *sch, s32 cpu, u64 flags)
 {
 	struct rq *this_rq;
@@ -6638,6 +6666,8 @@ __bpf_kfunc void scx_bpf_events(struct scx_event_stats *events,
 __bpf_kfunc_end_defs();
 
 BTF_KFUNCS_START(scx_kfunc_ids_any)
+BTF_ID_FLAGS(func, scx_bpf_task_set_slice, KF_RCU);
+BTF_ID_FLAGS(func, scx_bpf_task_set_dsq_vtime, KF_RCU);
 BTF_ID_FLAGS(func, scx_bpf_kick_cpu)
 BTF_ID_FLAGS(func, scx_bpf_dsq_nr_queued)
 BTF_ID_FLAGS(func, scx_bpf_destroy_dsq)
diff --git a/tools/sched_ext/include/scx/common.bpf.h b/tools/sched_ext/include/scx/common.bpf.h
index 06e2551033cb..505231b7b7ae 100644
--- a/tools/sched_ext/include/scx/common.bpf.h
+++ b/tools/sched_ext/include/scx/common.bpf.h
@@ -102,6 +102,8 @@ s32 scx_bpf_pick_any_cpu_node(const cpumask_t *cpus_allowed, int node, u64 flags
 s32 scx_bpf_pick_any_cpu(const cpumask_t *cpus_allowed, u64 flags) __ksym;
 bool scx_bpf_task_running(const struct task_struct *p) __ksym;
 s32 scx_bpf_task_cpu(const struct task_struct *p) __ksym;
+bool scx_bpf_task_set_slice(struct task_struct *p, u64 slice) __ksym __weak;
+bool scx_bpf_task_set_dsq_vtime(struct task_struct *p, u64 vtime) __ksym __weak;
 struct rq *scx_bpf_cpu_rq(s32 cpu) __ksym;
 struct rq *scx_bpf_locked_rq(void) __ksym;
 struct task_struct *scx_bpf_cpu_curr(s32 cpu) __ksym __weak;
-- 
2.51.0


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH 3/4] sched_ext: Wrap kfunc args in struct to prepare for aux__prog
  2025-10-07  1:51 [PATCHSET sched_ext/for-6.19] sched_ext: Misc changes with some prep patches for sub-sched support Tejun Heo
  2025-10-07  1:51 ` [PATCH 1/4] tools/sched_ext: Strip compatibility macros for cgroup and dispatch APIs Tejun Heo
  2025-10-07  1:51 ` [PATCH 2/4] sched_ext: Add scx_bpf_task_set_slice() and scx_bpf_task_set_dsq_vtime() Tejun Heo
@ 2025-10-07  1:51 ` Tejun Heo
  2025-10-07  9:48   ` Andrea Righi
                     ` (2 more replies)
  2025-10-07  1:51 ` [PATCH 4/4] sched_ext: Make scx_bpf_dsq_insert*() return bool Tejun Heo
                   ` (2 subsequent siblings)
  5 siblings, 3 replies; 26+ messages in thread
From: Tejun Heo @ 2025-10-07  1:51 UTC (permalink / raw)
  To: David Vernet, Andrea Righi, Changwoo Min
  Cc: linux-kernel, sched-ext, Tejun Heo

scx_bpf_dsq_insert_vtime() and scx_bpf_select_cpu_and() currently have 5
parameters. An upcoming change will add aux__prog parameter which will exceed
BPF's 5 argument limit.

Prepare by adding new kfuncs __scx_bpf_dsq_insert_vtime() and
__scx_bpf_select_cpu_and() that take args structs. The existing kfuncs are
kept as compatibility wrappers. BPF programs use inline wrappers that detect
kernel API version via bpf_core_type_exists() and use the new struct-based
kfuncs when available, falling back to compat kfuncs otherwise. This allows
BPF programs to work with both old and new kernels.

Signed-off-by: Tejun Heo <tj@kernel.org>
---
 kernel/sched/ext.c                       | 82 ++++++++++++++++++------
 kernel/sched/ext_idle.c                  | 43 +++++++++++--
 tools/sched_ext/include/scx/common.bpf.h |  6 +-
 tools/sched_ext/include/scx/compat.bpf.h | 72 +++++++++++++++++++++
 4 files changed, 173 insertions(+), 30 deletions(-)

diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c
index 6d76efaaa9b2..a34e731229de 100644
--- a/kernel/sched/ext.c
+++ b/kernel/sched/ext.c
@@ -5345,54 +5345,94 @@ __bpf_kfunc void scx_bpf_dsq_insert(struct task_struct *p, u64 dsq_id, u64 slice
 	scx_dsq_insert_commit(sch, p, dsq_id, enq_flags);
 }
 
+static void scx_dsq_insert_vtime(struct scx_sched *sch, struct task_struct *p,
+				 u64 dsq_id, u64 slice, u64 vtime, u64 enq_flags)
+{
+	if (!scx_dsq_insert_preamble(sch, p, enq_flags))
+		return;
+
+	if (slice)
+		p->scx.slice = slice;
+	else
+		p->scx.slice = p->scx.slice ?: 1;
+
+	p->scx.dsq_vtime = vtime;
+
+	scx_dsq_insert_commit(sch, p, dsq_id, enq_flags | SCX_ENQ_DSQ_PRIQ);
+}
+
+struct scx_bpf_dsq_insert_vtime_args {
+	/* @p can't be packed together as KF_RCU is not transitive */
+	u64			dsq_id;
+	u64			slice;
+	u64			vtime;
+	u64			enq_flags;
+};
+
 /**
- * scx_bpf_dsq_insert_vtime - Insert a task into the vtime priority queue of a DSQ
+ * __scx_bpf_dsq_insert_vtime - Arg-wrapped vtime DSQ insertion
  * @p: task_struct to insert
- * @dsq_id: DSQ to insert into
- * @slice: duration @p can run for in nsecs, 0 to keep the current value
- * @vtime: @p's ordering inside the vtime-sorted queue of the target DSQ
- * @enq_flags: SCX_ENQ_*
+ * @args: struct containing the rest of the arguments
+ *       @args->dsq_id: DSQ to insert into
+ *       @args->slice: duration @p can run for in nsecs, 0 to keep the current value
+ *       @args->vtime: @p's ordering inside the vtime-sorted queue of the target DSQ
+ *       @args->enq_flags: SCX_ENQ_*
  *
- * Insert @p into the vtime priority queue of the DSQ identified by @dsq_id.
- * Tasks queued into the priority queue are ordered by @vtime. All other aspects
- * are identical to scx_bpf_dsq_insert().
+ * Wrapper kfunc that takes arguments via struct to work around BPF's 5 argument
+ * limit. BPF programs should use scx_bpf_dsq_insert_vtime() which is provided
+ * as an inline wrapper in common.bpf.h.
  *
- * @vtime ordering is according to time_before64() which considers wrapping. A
- * numerically larger vtime may indicate an earlier position in the ordering and
- * vice-versa.
+ * Insert @p into the vtime priority queue of the DSQ identified by
+ * @args->dsq_id. Tasks queued into the priority queue are ordered by
+ * @args->vtime. All other aspects are identical to scx_bpf_dsq_insert().
+ *
+ * @args->vtime ordering is according to time_before64() which considers
+ * wrapping. A numerically larger vtime may indicate an earlier position in the
+ * ordering and vice-versa.
  *
  * A DSQ can only be used as a FIFO or priority queue at any given time and this
  * function must not be called on a DSQ which already has one or more FIFO tasks
  * queued and vice-versa. Also, the built-in DSQs (SCX_DSQ_LOCAL and
  * SCX_DSQ_GLOBAL) cannot be used as priority queues.
  */
-__bpf_kfunc void scx_bpf_dsq_insert_vtime(struct task_struct *p, u64 dsq_id,
-					  u64 slice, u64 vtime, u64 enq_flags)
+__bpf_kfunc void
+__scx_bpf_dsq_insert_vtime(struct task_struct *p,
+			   struct scx_bpf_dsq_insert_vtime_args *args)
 {
 	struct scx_sched *sch;
 
 	guard(rcu)();
+
 	sch = rcu_dereference(scx_root);
 	if (unlikely(!sch))
 		return;
 
-	if (!scx_dsq_insert_preamble(sch, p, enq_flags))
-		return;
+	scx_dsq_insert_vtime(sch, p, args->dsq_id, args->slice, args->vtime,
+			     args->enq_flags);
+}
 
-	if (slice)
-		p->scx.slice = slice;
-	else
-		p->scx.slice = p->scx.slice ?: 1;
+/*
+ * COMPAT: Will be removed in v6.23.
+ */
+__bpf_kfunc void scx_bpf_dsq_insert_vtime(struct task_struct *p, u64 dsq_id,
+					  u64 slice, u64 vtime, u64 enq_flags)
+{
+	struct scx_sched *sch;
 
-	p->scx.dsq_vtime = vtime;
+	guard(rcu)();
 
-	scx_dsq_insert_commit(sch, p, dsq_id, enq_flags | SCX_ENQ_DSQ_PRIQ);
+	sch = rcu_dereference(scx_root);
+	if (unlikely(!sch))
+		return;
+
+	scx_dsq_insert_vtime(sch, p, dsq_id, slice, vtime, enq_flags);
 }
 
 __bpf_kfunc_end_defs();
 
 BTF_KFUNCS_START(scx_kfunc_ids_enqueue_dispatch)
 BTF_ID_FLAGS(func, scx_bpf_dsq_insert, KF_RCU)
+BTF_ID_FLAGS(func, __scx_bpf_dsq_insert_vtime, KF_RCU)
 BTF_ID_FLAGS(func, scx_bpf_dsq_insert_vtime, KF_RCU)
 BTF_KFUNCS_END(scx_kfunc_ids_enqueue_dispatch)
 
diff --git a/kernel/sched/ext_idle.c b/kernel/sched/ext_idle.c
index d2434c954848..3d9d404d5cd2 100644
--- a/kernel/sched/ext_idle.c
+++ b/kernel/sched/ext_idle.c
@@ -995,26 +995,56 @@ __bpf_kfunc s32 scx_bpf_select_cpu_dfl(struct task_struct *p, s32 prev_cpu,
 	return prev_cpu;
 }
 
+struct scx_bpf_select_cpu_and_args {
+	/* @p and @cpus_allowed can't be packed together as KF_RCU is not transitive */
+	s32			prev_cpu;
+	u64			wake_flags;
+	u64			flags;
+};
+
 /**
- * scx_bpf_select_cpu_and - Pick an idle CPU usable by task @p,
- *			    prioritizing those in @cpus_allowed
+ * __scx_bpf_select_cpu_and - Arg-wrapped CPU selection with cpumask
  * @p: task_struct to select a CPU for
- * @prev_cpu: CPU @p was on previously
- * @wake_flags: %SCX_WAKE_* flags
  * @cpus_allowed: cpumask of allowed CPUs
- * @flags: %SCX_PICK_IDLE* flags
+ * @args: struct containing the rest of the arguments
+ *       @args->prev_cpu: CPU @p was on previously
+ *       @args->wake_flags: %SCX_WAKE_* flags
+ *       @args->flags: %SCX_PICK_IDLE* flags
+ *
+ * Wrapper kfunc that takes arguments via struct to work around BPF's 5 argument
+ * limit. BPF programs should use scx_bpf_select_cpu_and() which is provided
+ * as an inline wrapper in common.bpf.h.
  *
  * Can be called from ops.select_cpu(), ops.enqueue(), or from an unlocked
  * context such as a BPF test_run() call, as long as built-in CPU selection
  * is enabled: ops.update_idle() is missing or %SCX_OPS_KEEP_BUILTIN_IDLE
  * is set.
  *
- * @p, @prev_cpu and @wake_flags match ops.select_cpu().
+ * @p, @args->prev_cpu and @args->wake_flags match ops.select_cpu().
  *
  * Returns the selected idle CPU, which will be automatically awakened upon
  * returning from ops.select_cpu() and can be used for direct dispatch, or
  * a negative value if no idle CPU is available.
  */
+__bpf_kfunc s32
+__scx_bpf_select_cpu_and(struct task_struct *p, const struct cpumask *cpus_allowed,
+			 struct scx_bpf_select_cpu_and_args *args)
+{
+	struct scx_sched *sch;
+
+	guard(rcu)();
+
+	sch = rcu_dereference(scx_root);
+	if (unlikely(!sch))
+		return -ENODEV;
+
+	return select_cpu_from_kfunc(sch, p, args->prev_cpu, args->wake_flags,
+				     cpus_allowed, args->flags);
+}
+
+/*
+ * COMPAT: Will be removed in v6.22.
+ */
 __bpf_kfunc s32 scx_bpf_select_cpu_and(struct task_struct *p, s32 prev_cpu, u64 wake_flags,
 				       const struct cpumask *cpus_allowed, u64 flags)
 {
@@ -1383,6 +1413,7 @@ BTF_ID_FLAGS(func, scx_bpf_pick_idle_cpu_node, KF_RCU)
 BTF_ID_FLAGS(func, scx_bpf_pick_idle_cpu, KF_RCU)
 BTF_ID_FLAGS(func, scx_bpf_pick_any_cpu_node, KF_RCU)
 BTF_ID_FLAGS(func, scx_bpf_pick_any_cpu, KF_RCU)
+BTF_ID_FLAGS(func, __scx_bpf_select_cpu_and, KF_RCU)
 BTF_ID_FLAGS(func, scx_bpf_select_cpu_and, KF_RCU)
 BTF_ID_FLAGS(func, scx_bpf_select_cpu_dfl, KF_RCU)
 BTF_KFUNCS_END(scx_kfunc_ids_idle)
diff --git a/tools/sched_ext/include/scx/common.bpf.h b/tools/sched_ext/include/scx/common.bpf.h
index 505231b7b7ae..b1c2a0dde76e 100644
--- a/tools/sched_ext/include/scx/common.bpf.h
+++ b/tools/sched_ext/include/scx/common.bpf.h
@@ -60,10 +60,10 @@ static inline void ___vmlinux_h_sanity_check___(void)
 
 s32 scx_bpf_create_dsq(u64 dsq_id, s32 node) __ksym;
 s32 scx_bpf_select_cpu_dfl(struct task_struct *p, s32 prev_cpu, u64 wake_flags, bool *is_idle) __ksym;
-s32 scx_bpf_select_cpu_and(struct task_struct *p, s32 prev_cpu, u64 wake_flags,
-			   const struct cpumask *cpus_allowed, u64 flags) __ksym __weak;
+s32 __scx_bpf_select_cpu_and(struct task_struct *p, const struct cpumask *cpus_allowed,
+			     struct scx_bpf_select_cpu_and_args *args) __ksym __weak;
 void scx_bpf_dsq_insert(struct task_struct *p, u64 dsq_id, u64 slice, u64 enq_flags) __ksym __weak;
-void scx_bpf_dsq_insert_vtime(struct task_struct *p, u64 dsq_id, u64 slice, u64 vtime, u64 enq_flags) __ksym __weak;
+void __scx_bpf_dsq_insert_vtime(struct task_struct *p, struct scx_bpf_dsq_insert_vtime_args *args) __ksym __weak;
 u32 scx_bpf_dispatch_nr_slots(void) __ksym;
 void scx_bpf_dispatch_cancel(void) __ksym;
 bool scx_bpf_dsq_move_to_local(u64 dsq_id) __ksym __weak;
diff --git a/tools/sched_ext/include/scx/compat.bpf.h b/tools/sched_ext/include/scx/compat.bpf.h
index d979f16a3ae2..e172de696f99 100644
--- a/tools/sched_ext/include/scx/compat.bpf.h
+++ b/tools/sched_ext/include/scx/compat.bpf.h
@@ -143,6 +143,78 @@ static inline struct task_struct *__COMPAT_scx_bpf_cpu_curr(int cpu)
 	return rq ? rq->curr : NULL;
 }
 
+/*
+ * v6.19: To work around BPF maximum parameter limit, the following kfuncs are
+ * replaced with variants that pack scalar arguments in a struct. Wrappers are
+ * provided to maintain source compatibility.
+ *
+ * The kernel will carry the compat variants until v6.23 to maintain binary
+ * compatibility. After v6.23 release, remove the compat handling and move the
+ * wrappers to common.bpf.h.
+ */
+s32 scx_bpf_select_cpu_and___compat(struct task_struct *p, s32 prev_cpu, u64 wake_flags,
+				    const struct cpumask *cpus_allowed, u64 flags) __ksym __weak;
+void scx_bpf_dsq_insert_vtime___compat(struct task_struct *p, u64 dsq_id, u64 slice, u64 vtime, u64 enq_flags) __ksym __weak;
+
+/**
+ * scx_bpf_select_cpu_and - Pick an idle CPU usable by task @p
+ * @p: task_struct to select a CPU for
+ * @prev_cpu: CPU @p was on previously
+ * @wake_flags: %SCX_WAKE_* flags
+ * @cpus_allowed: cpumask of allowed CPUs
+ * @flags: %SCX_PICK_IDLE* flags
+ *
+ * Inline wrapper that packs scalar arguments into a struct and calls
+ * __scx_bpf_select_cpu_and(). See __scx_bpf_select_cpu_and() for details.
+ */
+static inline s32
+scx_bpf_select_cpu_and(struct task_struct *p, s32 prev_cpu, u64 wake_flags,
+		       const struct cpumask *cpus_allowed, u64 flags)
+{
+	if (bpf_core_type_exists(struct scx_bpf_select_cpu_and_args)) {
+		struct scx_bpf_select_cpu_and_args args = {
+			.prev_cpu = prev_cpu,
+			.wake_flags = wake_flags,
+			.flags = flags,
+		};
+
+		return __scx_bpf_select_cpu_and(p, cpus_allowed, &args);
+	} else {
+		return scx_bpf_select_cpu_and___compat(p, prev_cpu, wake_flags,
+						       cpus_allowed, flags);
+	}
+}
+
+/**
+ * scx_bpf_dsq_insert_vtime - Insert a task into the vtime priority queue of a DSQ
+ * @p: task_struct to insert
+ * @dsq_id: DSQ to insert into
+ * @slice: duration @p can run for in nsecs, 0 to keep the current value
+ * @vtime: @p's ordering inside the vtime-sorted queue of the target DSQ
+ * @enq_flags: SCX_ENQ_*
+ *
+ * Inline wrapper that packs scalar arguments into a struct and calls
+ * __scx_bpf_dsq_insert_vtime(). See __scx_bpf_dsq_insert_vtime() for details.
+ */
+static inline void
+scx_bpf_dsq_insert_vtime(struct task_struct *p, u64 dsq_id, u64 slice, u64 vtime,
+			 u64 enq_flags)
+{
+	if (bpf_core_type_exists(struct scx_bpf_dsq_insert_vtime_args)) {
+		struct scx_bpf_dsq_insert_vtime_args args = {
+			.dsq_id = dsq_id,
+			.slice = slice,
+			.vtime = vtime,
+			.enq_flags = enq_flags,
+		};
+
+		__scx_bpf_dsq_insert_vtime(p, &args);
+	} else {
+		scx_bpf_dsq_insert_vtime___compat(p, dsq_id, slice, vtime,
+						  enq_flags);
+	}
+}
+
 /*
  * Define sched_ext_ops. This may be expanded to define multiple variants for
  * backward compatibility. See compat.h::SCX_OPS_LOAD/ATTACH().
-- 
2.51.0


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH 4/4] sched_ext: Make scx_bpf_dsq_insert*() return bool
  2025-10-07  1:51 [PATCHSET sched_ext/for-6.19] sched_ext: Misc changes with some prep patches for sub-sched support Tejun Heo
                   ` (2 preceding siblings ...)
  2025-10-07  1:51 ` [PATCH 3/4] sched_ext: Wrap kfunc args in struct to prepare for aux__prog Tejun Heo
@ 2025-10-07  1:51 ` Tejun Heo
  2025-10-07  4:28   ` Emil Tsalapatis
                     ` (2 more replies)
  2025-10-07 19:06 ` [PATCH 5/4] sched_ext/tools: Add compat wrapper for scx_bpf_task_set_slice/dsq_vtime() Tejun Heo
  2025-10-13 18:53 ` [PATCHSET sched_ext/for-6.19] sched_ext: Misc changes with some prep patches for sub-sched support Tejun Heo
  5 siblings, 3 replies; 26+ messages in thread
From: Tejun Heo @ 2025-10-07  1:51 UTC (permalink / raw)
  To: David Vernet, Andrea Righi, Changwoo Min
  Cc: linux-kernel, sched-ext, Tejun Heo

In preparation for hierarchical schedulers, change scx_bpf_dsq_insert() and
scx_bpf_dsq_insert_vtime() to return bool instead of void. With
sub-schedulers, there will be no reliable way to guarantee a task is still
owned by the sub-scheduler at insertion time (e.g., the task may have been
migrated to another scheduler). The bool return value will enable
sub-schedulers to detect and gracefully handle insertion failures.

For the root scheduler, insertion failures will continue to trigger scheduler
abort via scx_error(), so existing code doesn't need to check the return
value. Backward compatibility is maintained through compat wrappers.

Also update scx_bpf_dsq_move() documentation to clarify that it can return
false for sub-schedulers when @dsq_id points to a disallowed local DSQ.

Signed-off-by: Tejun Heo <tj@kernel.org>
---
 kernel/sched/ext.c                       | 45 ++++++++++++++++++------
 tools/sched_ext/include/scx/common.bpf.h |  3 +-
 tools/sched_ext/include/scx/compat.bpf.h | 23 ++++++++++--
 3 files changed, 56 insertions(+), 15 deletions(-)

diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c
index a34e731229de..399e53c8939c 100644
--- a/kernel/sched/ext.c
+++ b/kernel/sched/ext.c
@@ -5323,8 +5323,12 @@ __bpf_kfunc_start_defs();
  * exhaustion. If zero, the current residual slice is maintained. If
  * %SCX_SLICE_INF, @p never expires and the BPF scheduler must kick the CPU with
  * scx_bpf_kick_cpu() to trigger scheduling.
+ *
+ * Returns %true on successful insertion, %false on failure. On the root
+ * scheduler, %false return triggers scheduler abort and the caller doesn't need
+ * to check the return value.
  */
-__bpf_kfunc void scx_bpf_dsq_insert(struct task_struct *p, u64 dsq_id, u64 slice,
+__bpf_kfunc bool scx_bpf_dsq_insert(struct task_struct *p, u64 dsq_id, u64 slice,
 				    u64 enq_flags)
 {
 	struct scx_sched *sch;
@@ -5332,10 +5336,10 @@ __bpf_kfunc void scx_bpf_dsq_insert(struct task_struct *p, u64 dsq_id, u64 slice
 	guard(rcu)();
 	sch = rcu_dereference(scx_root);
 	if (unlikely(!sch))
-		return;
+		return false;
 
 	if (!scx_dsq_insert_preamble(sch, p, enq_flags))
-		return;
+		return false;
 
 	if (slice)
 		p->scx.slice = slice;
@@ -5343,13 +5347,24 @@ __bpf_kfunc void scx_bpf_dsq_insert(struct task_struct *p, u64 dsq_id, u64 slice
 		p->scx.slice = p->scx.slice ?: 1;
 
 	scx_dsq_insert_commit(sch, p, dsq_id, enq_flags);
+
+	return true;
+}
+
+/*
+ * COMPAT: Will be removed in v6.23.
+ */
+__bpf_kfunc void scx_bpf_dsq_insert___compat(struct task_struct *p, u64 dsq_id,
+					     u64 slice, u64 enq_flags)
+{
+	scx_bpf_dsq_insert(p, dsq_id, slice, enq_flags);
 }
 
-static void scx_dsq_insert_vtime(struct scx_sched *sch, struct task_struct *p,
+static bool scx_dsq_insert_vtime(struct scx_sched *sch, struct task_struct *p,
 				 u64 dsq_id, u64 slice, u64 vtime, u64 enq_flags)
 {
 	if (!scx_dsq_insert_preamble(sch, p, enq_flags))
-		return;
+		return false;
 
 	if (slice)
 		p->scx.slice = slice;
@@ -5359,6 +5374,8 @@ static void scx_dsq_insert_vtime(struct scx_sched *sch, struct task_struct *p,
 	p->scx.dsq_vtime = vtime;
 
 	scx_dsq_insert_commit(sch, p, dsq_id, enq_flags | SCX_ENQ_DSQ_PRIQ);
+
+	return true;
 }
 
 struct scx_bpf_dsq_insert_vtime_args {
@@ -5394,8 +5411,12 @@ struct scx_bpf_dsq_insert_vtime_args {
  * function must not be called on a DSQ which already has one or more FIFO tasks
  * queued and vice-versa. Also, the built-in DSQs (SCX_DSQ_LOCAL and
  * SCX_DSQ_GLOBAL) cannot be used as priority queues.
+ *
+ * Returns %true on successful insertion, %false on failure. On the root
+ * scheduler, %false return triggers scheduler abort and the caller doesn't need
+ * to check the return value.
  */
-__bpf_kfunc void
+__bpf_kfunc bool
 __scx_bpf_dsq_insert_vtime(struct task_struct *p,
 			   struct scx_bpf_dsq_insert_vtime_args *args)
 {
@@ -5405,10 +5426,10 @@ __scx_bpf_dsq_insert_vtime(struct task_struct *p,
 
 	sch = rcu_dereference(scx_root);
 	if (unlikely(!sch))
-		return;
+		return false;
 
-	scx_dsq_insert_vtime(sch, p, args->dsq_id, args->slice, args->vtime,
-			     args->enq_flags);
+	return scx_dsq_insert_vtime(sch, p, args->dsq_id, args->slice,
+				    args->vtime, args->enq_flags);
 }
 
 /*
@@ -5432,6 +5453,7 @@ __bpf_kfunc_end_defs();
 
 BTF_KFUNCS_START(scx_kfunc_ids_enqueue_dispatch)
 BTF_ID_FLAGS(func, scx_bpf_dsq_insert, KF_RCU)
+BTF_ID_FLAGS(func, scx_bpf_dsq_insert___compat, KF_RCU)
 BTF_ID_FLAGS(func, __scx_bpf_dsq_insert_vtime, KF_RCU)
 BTF_ID_FLAGS(func, scx_bpf_dsq_insert_vtime, KF_RCU)
 BTF_KFUNCS_END(scx_kfunc_ids_enqueue_dispatch)
@@ -5686,8 +5708,9 @@ __bpf_kfunc void scx_bpf_dsq_move_set_vtime(struct bpf_iter_scx_dsq *it__iter,
  * Can be called from ops.dispatch() or any BPF context which doesn't hold a rq
  * lock (e.g. BPF timers or SYSCALL programs).
  *
- * Returns %true if @p has been consumed, %false if @p had already been consumed
- * or dequeued.
+ * Returns %true if @p has been consumed, %false if @p had already been
+ * consumed, dequeued, or, for sub-scheds, @dsq_id points to a disallowed local
+ * DSQ.
  */
 __bpf_kfunc bool scx_bpf_dsq_move(struct bpf_iter_scx_dsq *it__iter,
 				  struct task_struct *p, u64 dsq_id,
diff --git a/tools/sched_ext/include/scx/common.bpf.h b/tools/sched_ext/include/scx/common.bpf.h
index b1c2a0dde76e..522c90d0ced2 100644
--- a/tools/sched_ext/include/scx/common.bpf.h
+++ b/tools/sched_ext/include/scx/common.bpf.h
@@ -62,8 +62,7 @@ s32 scx_bpf_create_dsq(u64 dsq_id, s32 node) __ksym;
 s32 scx_bpf_select_cpu_dfl(struct task_struct *p, s32 prev_cpu, u64 wake_flags, bool *is_idle) __ksym;
 s32 __scx_bpf_select_cpu_and(struct task_struct *p, const struct cpumask *cpus_allowed,
 			     struct scx_bpf_select_cpu_and_args *args) __ksym __weak;
-void scx_bpf_dsq_insert(struct task_struct *p, u64 dsq_id, u64 slice, u64 enq_flags) __ksym __weak;
-void __scx_bpf_dsq_insert_vtime(struct task_struct *p, struct scx_bpf_dsq_insert_vtime_args *args) __ksym __weak;
+bool __scx_bpf_dsq_insert_vtime(struct task_struct *p, struct scx_bpf_dsq_insert_vtime_args *args) __ksym __weak;
 u32 scx_bpf_dispatch_nr_slots(void) __ksym;
 void scx_bpf_dispatch_cancel(void) __ksym;
 bool scx_bpf_dsq_move_to_local(u64 dsq_id) __ksym __weak;
diff --git a/tools/sched_ext/include/scx/compat.bpf.h b/tools/sched_ext/include/scx/compat.bpf.h
index e172de696f99..33c26928f4e9 100644
--- a/tools/sched_ext/include/scx/compat.bpf.h
+++ b/tools/sched_ext/include/scx/compat.bpf.h
@@ -196,7 +196,7 @@ scx_bpf_select_cpu_and(struct task_struct *p, s32 prev_cpu, u64 wake_flags,
  * Inline wrapper that packs scalar arguments into a struct and calls
  * __scx_bpf_dsq_insert_vtime(). See __scx_bpf_dsq_insert_vtime() for details.
  */
-static inline void
+static inline bool
 scx_bpf_dsq_insert_vtime(struct task_struct *p, u64 dsq_id, u64 slice, u64 vtime,
 			 u64 enq_flags)
 {
@@ -208,10 +208,29 @@ scx_bpf_dsq_insert_vtime(struct task_struct *p, u64 dsq_id, u64 slice, u64 vtime
 			.enq_flags = enq_flags,
 		};
 
-		__scx_bpf_dsq_insert_vtime(p, &args);
+		return __scx_bpf_dsq_insert_vtime(p, &args);
 	} else {
 		scx_bpf_dsq_insert_vtime___compat(p, dsq_id, slice, vtime,
 						  enq_flags);
+		return true;
+	}
+}
+
+/*
+ * v6.19: scx_bpf_dsq_insert() now returns bool instead of void. Move
+ * scx_bpf_dsq_insert() decl to common.bpf.h and drop compat helper after v6.22.
+ */
+bool scx_bpf_dsq_insert___new(struct task_struct *p, u64 dsq_id, u64 slice, u64 enq_flags) __ksym __weak;
+void scx_bpf_dsq_insert___compat(struct task_struct *p, u64 dsq_id, u64 slice, u64 enq_flags) __ksym __weak;
+
+static inline bool
+scx_bpf_dsq_insert(struct task_struct *p, u64 dsq_id, u64 slice, u64 enq_flags)
+{
+	if (bpf_ksym_exists(scx_bpf_dsq_insert___new)) {
+		return scx_bpf_dsq_insert___new(p, dsq_id, slice, enq_flags);
+	} else {
+		scx_bpf_dsq_insert___compat(p, dsq_id, slice, enq_flags);
+		return true;
 	}
 }
 
-- 
2.51.0


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* Re: [PATCH 1/4] tools/sched_ext: Strip compatibility macros for cgroup and dispatch APIs
  2025-10-07  1:51 ` [PATCH 1/4] tools/sched_ext: Strip compatibility macros for cgroup and dispatch APIs Tejun Heo
@ 2025-10-07  2:42   ` Emil Tsalapatis
  2025-10-07  9:42   ` Andrea Righi
  2025-10-07 16:22   ` Changwoo Min
  2 siblings, 0 replies; 26+ messages in thread
From: Emil Tsalapatis @ 2025-10-07  2:42 UTC (permalink / raw)
  To: Tejun Heo
  Cc: David Vernet, Andrea Righi, Changwoo Min, linux-kernel, sched-ext

On Mon, Oct 6, 2025 at 9:51 PM Tejun Heo <tj@kernel.org> wrote:
>
> Enough time has passed since the introduction of scx_bpf_task_cgroup() and
> the scx_bpf_dispatch* -> scx_bpf_dsq* kfunc renaming. Strip the compatibility
> macros.
>
> Signed-off-by: Tejun Heo <tj@kernel.org>

Reviewed-by: Emil Tsalapatis <emil@etsalapatis.com>

> ---
>  tools/sched_ext/include/scx/compat.bpf.h | 108 +----------------------
>  tools/sched_ext/scx_flatcg.bpf.c         |  10 +--
>  tools/sched_ext/scx_qmap.bpf.c           |  14 ++-
>  3 files changed, 12 insertions(+), 120 deletions(-)
>
> diff --git a/tools/sched_ext/include/scx/compat.bpf.h b/tools/sched_ext/include/scx/compat.bpf.h
> index dd9144624dc9..d979f16a3ae2 100644
> --- a/tools/sched_ext/include/scx/compat.bpf.h
> +++ b/tools/sched_ext/include/scx/compat.bpf.h
> @@ -15,121 +15,17 @@
>         __ret;                                                                  \
>  })
>
> -/* v6.12: 819513666966 ("sched_ext: Add cgroup support") */
> -#define __COMPAT_scx_bpf_task_cgroup(p)                                                \
> -       (bpf_ksym_exists(scx_bpf_task_cgroup) ?                                 \
> -        scx_bpf_task_cgroup((p)) : NULL)
> -
>  /*
> - * v6.13: The verb `dispatch` was too overloaded and confusing. kfuncs are
> - * renamed to unload the verb.
> - *
> - * Build error is triggered if old names are used. New binaries work with both
> - * new and old names. The compat macros will be removed on v6.15 release.
> + * v6.15: 950ad93df2fc ("bpf: add kfunc for populating cpumask bits")
>   *
> - * scx_bpf_dispatch_from_dsq() and friends were added during v6.12 by
> - * 4c30f5ce4f7a ("sched_ext: Implement scx_bpf_dispatch[_vtime]_from_dsq()").
> - * Preserve __COMPAT macros until v6.15.
> + * Compat macro will be dropped on v6.19 release.
>   */
> -void scx_bpf_dispatch___compat(struct task_struct *p, u64 dsq_id, u64 slice, u64 enq_flags) __ksym __weak;
> -void scx_bpf_dispatch_vtime___compat(struct task_struct *p, u64 dsq_id, u64 slice, u64 vtime, u64 enq_flags) __ksym __weak;
> -bool scx_bpf_consume___compat(u64 dsq_id) __ksym __weak;
> -void scx_bpf_dispatch_from_dsq_set_slice___compat(struct bpf_iter_scx_dsq *it__iter, u64 slice) __ksym __weak;
> -void scx_bpf_dispatch_from_dsq_set_vtime___compat(struct bpf_iter_scx_dsq *it__iter, u64 vtime) __ksym __weak;
> -bool scx_bpf_dispatch_from_dsq___compat(struct bpf_iter_scx_dsq *it__iter, struct task_struct *p, u64 dsq_id, u64 enq_flags) __ksym __weak;
> -bool scx_bpf_dispatch_vtime_from_dsq___compat(struct bpf_iter_scx_dsq *it__iter, struct task_struct *p, u64 dsq_id, u64 enq_flags) __ksym __weak;
>  int bpf_cpumask_populate(struct cpumask *dst, void *src, size_t src__sz) __ksym __weak;
>
> -#define scx_bpf_dsq_insert(p, dsq_id, slice, enq_flags)                                \
> -       (bpf_ksym_exists(scx_bpf_dsq_insert) ?                                  \
> -        scx_bpf_dsq_insert((p), (dsq_id), (slice), (enq_flags)) :              \
> -        scx_bpf_dispatch___compat((p), (dsq_id), (slice), (enq_flags)))
> -
> -#define scx_bpf_dsq_insert_vtime(p, dsq_id, slice, vtime, enq_flags)           \
> -       (bpf_ksym_exists(scx_bpf_dsq_insert_vtime) ?                            \
> -        scx_bpf_dsq_insert_vtime((p), (dsq_id), (slice), (vtime), (enq_flags)) : \
> -        scx_bpf_dispatch_vtime___compat((p), (dsq_id), (slice), (vtime), (enq_flags)))
> -
> -#define scx_bpf_dsq_move_to_local(dsq_id)                                      \
> -       (bpf_ksym_exists(scx_bpf_dsq_move_to_local) ?                           \
> -        scx_bpf_dsq_move_to_local((dsq_id)) :                                  \
> -        scx_bpf_consume___compat((dsq_id)))
> -
> -#define __COMPAT_scx_bpf_dsq_move_set_slice(it__iter, slice)                   \
> -       (bpf_ksym_exists(scx_bpf_dsq_move_set_slice) ?                          \
> -        scx_bpf_dsq_move_set_slice((it__iter), (slice)) :                      \
> -        (bpf_ksym_exists(scx_bpf_dispatch_from_dsq_set_slice___compat) ?       \
> -         scx_bpf_dispatch_from_dsq_set_slice___compat((it__iter), (slice)) :   \
> -         (void)0))
> -
> -#define __COMPAT_scx_bpf_dsq_move_set_vtime(it__iter, vtime)                   \
> -       (bpf_ksym_exists(scx_bpf_dsq_move_set_vtime) ?                          \
> -        scx_bpf_dsq_move_set_vtime((it__iter), (vtime)) :                      \
> -        (bpf_ksym_exists(scx_bpf_dispatch_from_dsq_set_vtime___compat) ?       \
> -         scx_bpf_dispatch_from_dsq_set_vtime___compat((it__iter), (vtime)) :   \
> -         (void) 0))
> -
> -#define __COMPAT_scx_bpf_dsq_move(it__iter, p, dsq_id, enq_flags)              \
> -       (bpf_ksym_exists(scx_bpf_dsq_move) ?                                    \
> -        scx_bpf_dsq_move((it__iter), (p), (dsq_id), (enq_flags)) :             \
> -        (bpf_ksym_exists(scx_bpf_dispatch_from_dsq___compat) ?                 \
> -         scx_bpf_dispatch_from_dsq___compat((it__iter), (p), (dsq_id), (enq_flags)) : \
> -         false))
> -
> -#define __COMPAT_scx_bpf_dsq_move_vtime(it__iter, p, dsq_id, enq_flags)                \
> -       (bpf_ksym_exists(scx_bpf_dsq_move_vtime) ?                              \
> -        scx_bpf_dsq_move_vtime((it__iter), (p), (dsq_id), (enq_flags)) :       \
> -        (bpf_ksym_exists(scx_bpf_dispatch_vtime_from_dsq___compat) ?           \
> -         scx_bpf_dispatch_vtime_from_dsq___compat((it__iter), (p), (dsq_id), (enq_flags)) : \
> -         false))
> -
>  #define __COMPAT_bpf_cpumask_populate(cpumask, src, size__sz)          \
>         (bpf_ksym_exists(bpf_cpumask_populate) ?                        \
>          (bpf_cpumask_populate(cpumask, src, size__sz)) : -EOPNOTSUPP)
>
> -#define scx_bpf_dispatch(p, dsq_id, slice, enq_flags)                          \
> -       _Static_assert(false, "scx_bpf_dispatch() renamed to scx_bpf_dsq_insert()")
> -
> -#define scx_bpf_dispatch_vtime(p, dsq_id, slice, vtime, enq_flags)             \
> -       _Static_assert(false, "scx_bpf_dispatch_vtime() renamed to scx_bpf_dsq_insert_vtime()")
> -
> -#define scx_bpf_consume(dsq_id) ({                                             \
> -       _Static_assert(false, "scx_bpf_consume() renamed to scx_bpf_dsq_move_to_local()"); \
> -       false;                                                                  \
> -})
> -
> -#define scx_bpf_dispatch_from_dsq_set_slice(it__iter, slice)           \
> -       _Static_assert(false, "scx_bpf_dispatch_from_dsq_set_slice() renamed to scx_bpf_dsq_move_set_slice()")
> -
> -#define scx_bpf_dispatch_from_dsq_set_vtime(it__iter, vtime)           \
> -       _Static_assert(false, "scx_bpf_dispatch_from_dsq_set_vtime() renamed to scx_bpf_dsq_move_set_vtime()")
> -
> -#define scx_bpf_dispatch_from_dsq(it__iter, p, dsq_id, enq_flags) ({   \
> -       _Static_assert(false, "scx_bpf_dispatch_from_dsq() renamed to scx_bpf_dsq_move()"); \
> -       false;                                                                  \
> -})
> -
> -#define scx_bpf_dispatch_vtime_from_dsq(it__iter, p, dsq_id, enq_flags) ({  \
> -       _Static_assert(false, "scx_bpf_dispatch_vtime_from_dsq() renamed to scx_bpf_dsq_move_vtime()"); \
> -       false;                                                                  \
> -})
> -
> -#define __COMPAT_scx_bpf_dispatch_from_dsq_set_slice(it__iter, slice)          \
> -       _Static_assert(false, "__COMPAT_scx_bpf_dispatch_from_dsq_set_slice() renamed to __COMPAT_scx_bpf_dsq_move_set_slice()")
> -
> -#define __COMPAT_scx_bpf_dispatch_from_dsq_set_vtime(it__iter, vtime)          \
> -       _Static_assert(false, "__COMPAT_scx_bpf_dispatch_from_dsq_set_vtime() renamed to __COMPAT_scx_bpf_dsq_move_set_vtime()")
> -
> -#define __COMPAT_scx_bpf_dispatch_from_dsq(it__iter, p, dsq_id, enq_flags) ({  \
> -       _Static_assert(false, "__COMPAT_scx_bpf_dispatch_from_dsq() renamed to __COMPAT_scx_bpf_dsq_move()"); \
> -       false;                                                                  \
> -})
> -
> -#define __COMPAT_scx_bpf_dispatch_vtime_from_dsq(it__iter, p, dsq_id, enq_flags) ({  \
> -       _Static_assert(false, "__COMPAT_scx_bpf_dispatch_vtime_from_dsq() renamed to __COMPAT_scx_bpf_dsq_move_vtime()"); \
> -       false;                                                                  \
> -})
> -
>  /**
>   * __COMPAT_is_enq_cpu_selected - Test if SCX_ENQ_CPU_SELECTED is on
>   * in a compatible way. We will preserve this __COMPAT helper until v6.16.
> diff --git a/tools/sched_ext/scx_flatcg.bpf.c b/tools/sched_ext/scx_flatcg.bpf.c
> index 2c720e3ecad5..43126858b8e4 100644
> --- a/tools/sched_ext/scx_flatcg.bpf.c
> +++ b/tools/sched_ext/scx_flatcg.bpf.c
> @@ -382,7 +382,7 @@ void BPF_STRUCT_OPS(fcg_enqueue, struct task_struct *p, u64 enq_flags)
>                 return;
>         }
>
> -       cgrp = __COMPAT_scx_bpf_task_cgroup(p);
> +       cgrp = scx_bpf_task_cgroup(p);
>         cgc = find_cgrp_ctx(cgrp);
>         if (!cgc)
>                 goto out_release;
> @@ -508,7 +508,7 @@ void BPF_STRUCT_OPS(fcg_runnable, struct task_struct *p, u64 enq_flags)
>  {
>         struct cgroup *cgrp;
>
> -       cgrp = __COMPAT_scx_bpf_task_cgroup(p);
> +       cgrp = scx_bpf_task_cgroup(p);
>         update_active_weight_sums(cgrp, true);
>         bpf_cgroup_release(cgrp);
>  }
> @@ -521,7 +521,7 @@ void BPF_STRUCT_OPS(fcg_running, struct task_struct *p)
>         if (fifo_sched)
>                 return;
>
> -       cgrp = __COMPAT_scx_bpf_task_cgroup(p);
> +       cgrp = scx_bpf_task_cgroup(p);
>         cgc = find_cgrp_ctx(cgrp);
>         if (cgc) {
>                 /*
> @@ -564,7 +564,7 @@ void BPF_STRUCT_OPS(fcg_stopping, struct task_struct *p, bool runnable)
>         if (!taskc->bypassed_at)
>                 return;
>
> -       cgrp = __COMPAT_scx_bpf_task_cgroup(p);
> +       cgrp = scx_bpf_task_cgroup(p);
>         cgc = find_cgrp_ctx(cgrp);
>         if (cgc) {
>                 __sync_fetch_and_add(&cgc->cvtime_delta,
> @@ -578,7 +578,7 @@ void BPF_STRUCT_OPS(fcg_quiescent, struct task_struct *p, u64 deq_flags)
>  {
>         struct cgroup *cgrp;
>
> -       cgrp = __COMPAT_scx_bpf_task_cgroup(p);
> +       cgrp = scx_bpf_task_cgroup(p);
>         update_active_weight_sums(cgrp, false);
>         bpf_cgroup_release(cgrp);
>  }
> diff --git a/tools/sched_ext/scx_qmap.bpf.c b/tools/sched_ext/scx_qmap.bpf.c
> index 3072b593f898..c67dac78a4c6 100644
> --- a/tools/sched_ext/scx_qmap.bpf.c
> +++ b/tools/sched_ext/scx_qmap.bpf.c
> @@ -320,12 +320,9 @@ static bool dispatch_highpri(bool from_timer)
>
>                 if (tctx->highpri) {
>                         /* exercise the set_*() and vtime interface too */
> -                       __COMPAT_scx_bpf_dsq_move_set_slice(
> -                               BPF_FOR_EACH_ITER, slice_ns * 2);
> -                       __COMPAT_scx_bpf_dsq_move_set_vtime(
> -                               BPF_FOR_EACH_ITER, highpri_seq++);
> -                       __COMPAT_scx_bpf_dsq_move_vtime(
> -                               BPF_FOR_EACH_ITER, p, HIGHPRI_DSQ, 0);
> +                       scx_bpf_dsq_move_set_slice(BPF_FOR_EACH_ITER, slice_ns * 2);
> +                       scx_bpf_dsq_move_set_vtime(BPF_FOR_EACH_ITER, highpri_seq++);
> +                       scx_bpf_dsq_move_vtime(BPF_FOR_EACH_ITER, p, HIGHPRI_DSQ, 0);
>                 }
>         }
>
> @@ -342,9 +339,8 @@ static bool dispatch_highpri(bool from_timer)
>                 else
>                         cpu = scx_bpf_pick_any_cpu(p->cpus_ptr, 0);
>
> -               if (__COMPAT_scx_bpf_dsq_move(BPF_FOR_EACH_ITER, p,
> -                                             SCX_DSQ_LOCAL_ON | cpu,
> -                                             SCX_ENQ_PREEMPT)) {
> +               if (scx_bpf_dsq_move(BPF_FOR_EACH_ITER, p, SCX_DSQ_LOCAL_ON | cpu,
> +                                    SCX_ENQ_PREEMPT)) {
>                         if (cpu == this_cpu) {
>                                 dispatched = true;
>                                 __sync_fetch_and_add(&nr_expedited_local, 1);
> --
> 2.51.0
>
>

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 2/4] sched_ext: Add scx_bpf_task_set_slice() and scx_bpf_task_set_dsq_vtime()
  2025-10-07  1:51 ` [PATCH 2/4] sched_ext: Add scx_bpf_task_set_slice() and scx_bpf_task_set_dsq_vtime() Tejun Heo
@ 2025-10-07  2:56   ` Emil Tsalapatis
  2025-10-07 18:09     ` Tejun Heo
  2025-10-07  9:34   ` Andrea Righi
  2025-10-07 16:28   ` Changwoo Min
  2 siblings, 1 reply; 26+ messages in thread
From: Emil Tsalapatis @ 2025-10-07  2:56 UTC (permalink / raw)
  To: Tejun Heo
  Cc: David Vernet, Andrea Righi, Changwoo Min, linux-kernel, sched-ext

On Mon, Oct 6, 2025 at 9:51 PM Tejun Heo <tj@kernel.org> wrote:
>
> With the planned hierarchical scheduler support, sub-schedulers will need to
> be verified for authority before being allowed to modify task->scx.slice and
> task->scx.dsq_vtime. Add scx_bpf_task_set_slice() and
> scx_bpf_task_set_dsq_vtime() which will perform the necessary permission
> checks.
>
> Root schedulers can still directly write to these fields, so this doesn't
> affect existing schedulers.
>
> Signed-off-by: Tejun Heo <tj@kernel.org>
Reviewed-by: Emil Tsalapatis <emil@etsalapatis.com>

> ---
>  kernel/sched/ext.c                       | 30 ++++++++++++++++++++++++
>  tools/sched_ext/include/scx/common.bpf.h |  2 ++
>  2 files changed, 32 insertions(+)
>
> diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c
> index fc353b8d69f7..6d76efaaa9b2 100644
> --- a/kernel/sched/ext.c
> +++ b/kernel/sched/ext.c
> @@ -5833,6 +5833,34 @@ static const struct btf_kfunc_id_set scx_kfunc_set_unlocked = {
>
>  __bpf_kfunc_start_defs();
>
> +/**
> + * scx_bpf_task_set_slice - Set task's time slice
> + * @p: task of interest
> + * @slice: time slice to set in nsecs
> + *
> + * Set @p's time slice to @slice. Returns %true on success, %false if the
> + * calling scheduler doesn't have authority over @p.
> + */
> +__bpf_kfunc bool scx_bpf_task_set_slice(struct task_struct *p, u64 slice)
> +{
> +       p->scx.slice = slice;
> +       return true;
> +}
> +

Q: Do we care about protecting slice/dsq_vtime these fields with a
lock (e.g., to let them be atomically changed w/ other
proc/DSQ state? If so, should we limit them with the kf_mask to be
callable from specific BPF ops?

> +/**
> + * scx_bpf_task_set_dsq_vtime - Set task's virtual time for DSQ ordering
> + * @p: task of interest
> + * @vtime: virtual time to set
> + *
> + * Set @p's virtual time to @vtime. Returns %true on success, %false if the
> + * calling scheduler doesn't have authority over @p.
> + */
> +__bpf_kfunc bool scx_bpf_task_set_dsq_vtime(struct task_struct *p, u64 vtime)
> +{
> +       p->scx.dsq_vtime = vtime;
> +       return true;
> +}
> +
>  static void scx_kick_cpu(struct scx_sched *sch, s32 cpu, u64 flags)
>  {
>         struct rq *this_rq;
> @@ -6638,6 +6666,8 @@ __bpf_kfunc void scx_bpf_events(struct scx_event_stats *events,
>  __bpf_kfunc_end_defs();
>
>  BTF_KFUNCS_START(scx_kfunc_ids_any)
> +BTF_ID_FLAGS(func, scx_bpf_task_set_slice, KF_RCU);
> +BTF_ID_FLAGS(func, scx_bpf_task_set_dsq_vtime, KF_RCU);
>  BTF_ID_FLAGS(func, scx_bpf_kick_cpu)
>  BTF_ID_FLAGS(func, scx_bpf_dsq_nr_queued)
>  BTF_ID_FLAGS(func, scx_bpf_destroy_dsq)
> diff --git a/tools/sched_ext/include/scx/common.bpf.h b/tools/sched_ext/include/scx/common.bpf.h
> index 06e2551033cb..505231b7b7ae 100644
> --- a/tools/sched_ext/include/scx/common.bpf.h
> +++ b/tools/sched_ext/include/scx/common.bpf.h
> @@ -102,6 +102,8 @@ s32 scx_bpf_pick_any_cpu_node(const cpumask_t *cpus_allowed, int node, u64 flags
>  s32 scx_bpf_pick_any_cpu(const cpumask_t *cpus_allowed, u64 flags) __ksym;
>  bool scx_bpf_task_running(const struct task_struct *p) __ksym;
>  s32 scx_bpf_task_cpu(const struct task_struct *p) __ksym;
> +bool scx_bpf_task_set_slice(struct task_struct *p, u64 slice) __ksym __weak;
> +bool scx_bpf_task_set_dsq_vtime(struct task_struct *p, u64 vtime) __ksym __weak;
>  struct rq *scx_bpf_cpu_rq(s32 cpu) __ksym;
>  struct rq *scx_bpf_locked_rq(void) __ksym;
>  struct task_struct *scx_bpf_cpu_curr(s32 cpu) __ksym __weak;
> --
> 2.51.0
>
>

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 4/4] sched_ext: Make scx_bpf_dsq_insert*() return bool
  2025-10-07  1:51 ` [PATCH 4/4] sched_ext: Make scx_bpf_dsq_insert*() return bool Tejun Heo
@ 2025-10-07  4:28   ` Emil Tsalapatis
  2025-10-07  9:41   ` Andrea Righi
  2025-10-07 16:47   ` Changwoo Min
  2 siblings, 0 replies; 26+ messages in thread
From: Emil Tsalapatis @ 2025-10-07  4:28 UTC (permalink / raw)
  To: Tejun Heo
  Cc: David Vernet, Andrea Righi, Changwoo Min, linux-kernel, sched-ext

On Mon, Oct 6, 2025 at 9:51 PM Tejun Heo <tj@kernel.org> wrote:
>
> In preparation for hierarchical schedulers, change scx_bpf_dsq_insert() and
> scx_bpf_dsq_insert_vtime() to return bool instead of void. With
> sub-schedulers, there will be no reliable way to guarantee a task is still
> owned by the sub-scheduler at insertion time (e.g., the task may have been
> migrated to another scheduler). The bool return value will enable
> sub-schedulers to detect and gracefully handle insertion failures.
>
> For the root scheduler, insertion failures will continue to trigger scheduler
> abort via scx_error(), so existing code doesn't need to check the return
> value. Backward compatibility is maintained through compat wrappers.
>
> Also update scx_bpf_dsq_move() documentation to clarify that it can return
> false for sub-schedulers when @dsq_id points to a disallowed local DSQ.
>
> Signed-off-by: Tejun Heo <tj@kernel.org>

Reviewed-by: Emil Tsalapatis <emil@etsalapatis.com>

> ---
>  kernel/sched/ext.c                       | 45 ++++++++++++++++++------
>  tools/sched_ext/include/scx/common.bpf.h |  3 +-
>  tools/sched_ext/include/scx/compat.bpf.h | 23 ++++++++++--
>  3 files changed, 56 insertions(+), 15 deletions(-)
>
> diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c
> index a34e731229de..399e53c8939c 100644
> --- a/kernel/sched/ext.c
> +++ b/kernel/sched/ext.c
> @@ -5323,8 +5323,12 @@ __bpf_kfunc_start_defs();
>   * exhaustion. If zero, the current residual slice is maintained. If
>   * %SCX_SLICE_INF, @p never expires and the BPF scheduler must kick the CPU with
>   * scx_bpf_kick_cpu() to trigger scheduling.
> + *
> + * Returns %true on successful insertion, %false on failure. On the root
> + * scheduler, %false return triggers scheduler abort and the caller doesn't need
> + * to check the return value.
>   */
> -__bpf_kfunc void scx_bpf_dsq_insert(struct task_struct *p, u64 dsq_id, u64 slice,
> +__bpf_kfunc bool scx_bpf_dsq_insert(struct task_struct *p, u64 dsq_id, u64 slice,
>                                     u64 enq_flags)
>  {
>         struct scx_sched *sch;
> @@ -5332,10 +5336,10 @@ __bpf_kfunc void scx_bpf_dsq_insert(struct task_struct *p, u64 dsq_id, u64 slice
>         guard(rcu)();
>         sch = rcu_dereference(scx_root);
>         if (unlikely(!sch))
> -               return;
> +               return false;
>
>         if (!scx_dsq_insert_preamble(sch, p, enq_flags))
> -               return;
> +               return false;
>
>         if (slice)
>                 p->scx.slice = slice;
> @@ -5343,13 +5347,24 @@ __bpf_kfunc void scx_bpf_dsq_insert(struct task_struct *p, u64 dsq_id, u64 slice
>                 p->scx.slice = p->scx.slice ?: 1;
>
>         scx_dsq_insert_commit(sch, p, dsq_id, enq_flags);
> +
> +       return true;
> +}
> +
> +/*
> + * COMPAT: Will be removed in v6.23.
> + */
> +__bpf_kfunc void scx_bpf_dsq_insert___compat(struct task_struct *p, u64 dsq_id,
> +                                            u64 slice, u64 enq_flags)
> +{
> +       scx_bpf_dsq_insert(p, dsq_id, slice, enq_flags);
>  }
>
> -static void scx_dsq_insert_vtime(struct scx_sched *sch, struct task_struct *p,
> +static bool scx_dsq_insert_vtime(struct scx_sched *sch, struct task_struct *p,
>                                  u64 dsq_id, u64 slice, u64 vtime, u64 enq_flags)
>  {
>         if (!scx_dsq_insert_preamble(sch, p, enq_flags))
> -               return;
> +               return false;
>
>         if (slice)
>                 p->scx.slice = slice;
> @@ -5359,6 +5374,8 @@ static void scx_dsq_insert_vtime(struct scx_sched *sch, struct task_struct *p,
>         p->scx.dsq_vtime = vtime;
>
>         scx_dsq_insert_commit(sch, p, dsq_id, enq_flags | SCX_ENQ_DSQ_PRIQ);
> +
> +       return true;
>  }
>
>  struct scx_bpf_dsq_insert_vtime_args {
> @@ -5394,8 +5411,12 @@ struct scx_bpf_dsq_insert_vtime_args {
>   * function must not be called on a DSQ which already has one or more FIFO tasks
>   * queued and vice-versa. Also, the built-in DSQs (SCX_DSQ_LOCAL and
>   * SCX_DSQ_GLOBAL) cannot be used as priority queues.
> + *
> + * Returns %true on successful insertion, %false on failure. On the root
> + * scheduler, %false return triggers scheduler abort and the caller doesn't need
> + * to check the return value.
>   */
> -__bpf_kfunc void
> +__bpf_kfunc bool
>  __scx_bpf_dsq_insert_vtime(struct task_struct *p,
>                            struct scx_bpf_dsq_insert_vtime_args *args)
>  {
> @@ -5405,10 +5426,10 @@ __scx_bpf_dsq_insert_vtime(struct task_struct *p,
>
>         sch = rcu_dereference(scx_root);
>         if (unlikely(!sch))
> -               return;
> +               return false;
>
> -       scx_dsq_insert_vtime(sch, p, args->dsq_id, args->slice, args->vtime,
> -                            args->enq_flags);
> +       return scx_dsq_insert_vtime(sch, p, args->dsq_id, args->slice,
> +                                   args->vtime, args->enq_flags);
>  }
>
>  /*
> @@ -5432,6 +5453,7 @@ __bpf_kfunc_end_defs();
>
>  BTF_KFUNCS_START(scx_kfunc_ids_enqueue_dispatch)
>  BTF_ID_FLAGS(func, scx_bpf_dsq_insert, KF_RCU)
> +BTF_ID_FLAGS(func, scx_bpf_dsq_insert___compat, KF_RCU)
>  BTF_ID_FLAGS(func, __scx_bpf_dsq_insert_vtime, KF_RCU)
>  BTF_ID_FLAGS(func, scx_bpf_dsq_insert_vtime, KF_RCU)
>  BTF_KFUNCS_END(scx_kfunc_ids_enqueue_dispatch)
> @@ -5686,8 +5708,9 @@ __bpf_kfunc void scx_bpf_dsq_move_set_vtime(struct bpf_iter_scx_dsq *it__iter,
>   * Can be called from ops.dispatch() or any BPF context which doesn't hold a rq
>   * lock (e.g. BPF timers or SYSCALL programs).
>   *
> - * Returns %true if @p has been consumed, %false if @p had already been consumed
> - * or dequeued.
> + * Returns %true if @p has been consumed, %false if @p had already been
> + * consumed, dequeued, or, for sub-scheds, @dsq_id points to a disallowed local
> + * DSQ.
>   */
>  __bpf_kfunc bool scx_bpf_dsq_move(struct bpf_iter_scx_dsq *it__iter,
>                                   struct task_struct *p, u64 dsq_id,
> diff --git a/tools/sched_ext/include/scx/common.bpf.h b/tools/sched_ext/include/scx/common.bpf.h
> index b1c2a0dde76e..522c90d0ced2 100644
> --- a/tools/sched_ext/include/scx/common.bpf.h
> +++ b/tools/sched_ext/include/scx/common.bpf.h
> @@ -62,8 +62,7 @@ s32 scx_bpf_create_dsq(u64 dsq_id, s32 node) __ksym;
>  s32 scx_bpf_select_cpu_dfl(struct task_struct *p, s32 prev_cpu, u64 wake_flags, bool *is_idle) __ksym;
>  s32 __scx_bpf_select_cpu_and(struct task_struct *p, const struct cpumask *cpus_allowed,
>                              struct scx_bpf_select_cpu_and_args *args) __ksym __weak;
> -void scx_bpf_dsq_insert(struct task_struct *p, u64 dsq_id, u64 slice, u64 enq_flags) __ksym __weak;
> -void __scx_bpf_dsq_insert_vtime(struct task_struct *p, struct scx_bpf_dsq_insert_vtime_args *args) __ksym __weak;
> +bool __scx_bpf_dsq_insert_vtime(struct task_struct *p, struct scx_bpf_dsq_insert_vtime_args *args) __ksym __weak;
>  u32 scx_bpf_dispatch_nr_slots(void) __ksym;
>  void scx_bpf_dispatch_cancel(void) __ksym;
>  bool scx_bpf_dsq_move_to_local(u64 dsq_id) __ksym __weak;
> diff --git a/tools/sched_ext/include/scx/compat.bpf.h b/tools/sched_ext/include/scx/compat.bpf.h
> index e172de696f99..33c26928f4e9 100644
> --- a/tools/sched_ext/include/scx/compat.bpf.h
> +++ b/tools/sched_ext/include/scx/compat.bpf.h
> @@ -196,7 +196,7 @@ scx_bpf_select_cpu_and(struct task_struct *p, s32 prev_cpu, u64 wake_flags,
>   * Inline wrapper that packs scalar arguments into a struct and calls
>   * __scx_bpf_dsq_insert_vtime(). See __scx_bpf_dsq_insert_vtime() for details.
>   */
> -static inline void
> +static inline bool
>  scx_bpf_dsq_insert_vtime(struct task_struct *p, u64 dsq_id, u64 slice, u64 vtime,
>                          u64 enq_flags)
>  {
> @@ -208,10 +208,29 @@ scx_bpf_dsq_insert_vtime(struct task_struct *p, u64 dsq_id, u64 slice, u64 vtime
>                         .enq_flags = enq_flags,
>                 };
>
> -               __scx_bpf_dsq_insert_vtime(p, &args);
> +               return __scx_bpf_dsq_insert_vtime(p, &args);
>         } else {
>                 scx_bpf_dsq_insert_vtime___compat(p, dsq_id, slice, vtime,
>                                                   enq_flags);
> +               return true;
> +       }
> +}
> +
> +/*
> + * v6.19: scx_bpf_dsq_insert() now returns bool instead of void. Move
> + * scx_bpf_dsq_insert() decl to common.bpf.h and drop compat helper after v6.22.
> + */
> +bool scx_bpf_dsq_insert___new(struct task_struct *p, u64 dsq_id, u64 slice, u64 enq_flags) __ksym __weak;
> +void scx_bpf_dsq_insert___compat(struct task_struct *p, u64 dsq_id, u64 slice, u64 enq_flags) __ksym __weak;
> +
> +static inline bool
> +scx_bpf_dsq_insert(struct task_struct *p, u64 dsq_id, u64 slice, u64 enq_flags)
> +{
> +       if (bpf_ksym_exists(scx_bpf_dsq_insert___new)) {
> +               return scx_bpf_dsq_insert___new(p, dsq_id, slice, enq_flags);
> +       } else {
> +               scx_bpf_dsq_insert___compat(p, dsq_id, slice, enq_flags);
> +               return true;
>         }
>  }
>


> --
> 2.51.0
>
>

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 2/4] sched_ext: Add scx_bpf_task_set_slice() and scx_bpf_task_set_dsq_vtime()
  2025-10-07  1:51 ` [PATCH 2/4] sched_ext: Add scx_bpf_task_set_slice() and scx_bpf_task_set_dsq_vtime() Tejun Heo
  2025-10-07  2:56   ` Emil Tsalapatis
@ 2025-10-07  9:34   ` Andrea Righi
  2025-10-07 18:09     ` Tejun Heo
  2025-10-07 16:28   ` Changwoo Min
  2 siblings, 1 reply; 26+ messages in thread
From: Andrea Righi @ 2025-10-07  9:34 UTC (permalink / raw)
  To: Tejun Heo; +Cc: David Vernet, Changwoo Min, linux-kernel, sched-ext

Hi Tejun,

On Mon, Oct 06, 2025 at 03:51:45PM -1000, Tejun Heo wrote:
> With the planned hierarchical scheduler support, sub-schedulers will need to
> be verified for authority before being allowed to modify task->scx.slice and
> task->scx.dsq_vtime. Add scx_bpf_task_set_slice() and
> scx_bpf_task_set_dsq_vtime() which will perform the necessary permission
> checks.
> 
> Root schedulers can still directly write to these fields, so this doesn't
> affect existing schedulers.
> 
> Signed-off-by: Tejun Heo <tj@kernel.org>
> ---

Maybe provide __COMPAT_scx_bpf_task_set_slice() and
__COMPAT_scx_bpf_task_set_dsq_vtime(), but we can do this later.

Thanks,
-Andrea

>  kernel/sched/ext.c                       | 30 ++++++++++++++++++++++++
>  tools/sched_ext/include/scx/common.bpf.h |  2 ++
>  2 files changed, 32 insertions(+)
> 
> diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c
> index fc353b8d69f7..6d76efaaa9b2 100644
> --- a/kernel/sched/ext.c
> +++ b/kernel/sched/ext.c
> @@ -5833,6 +5833,34 @@ static const struct btf_kfunc_id_set scx_kfunc_set_unlocked = {
>  
>  __bpf_kfunc_start_defs();
>  
> +/**
> + * scx_bpf_task_set_slice - Set task's time slice
> + * @p: task of interest
> + * @slice: time slice to set in nsecs
> + *
> + * Set @p's time slice to @slice. Returns %true on success, %false if the
> + * calling scheduler doesn't have authority over @p.
> + */
> +__bpf_kfunc bool scx_bpf_task_set_slice(struct task_struct *p, u64 slice)
> +{
> +	p->scx.slice = slice;
> +	return true;
> +}
> +
> +/**
> + * scx_bpf_task_set_dsq_vtime - Set task's virtual time for DSQ ordering
> + * @p: task of interest
> + * @vtime: virtual time to set
> + *
> + * Set @p's virtual time to @vtime. Returns %true on success, %false if the
> + * calling scheduler doesn't have authority over @p.
> + */
> +__bpf_kfunc bool scx_bpf_task_set_dsq_vtime(struct task_struct *p, u64 vtime)
> +{
> +	p->scx.dsq_vtime = vtime;
> +	return true;
> +}
> +
>  static void scx_kick_cpu(struct scx_sched *sch, s32 cpu, u64 flags)
>  {
>  	struct rq *this_rq;
> @@ -6638,6 +6666,8 @@ __bpf_kfunc void scx_bpf_events(struct scx_event_stats *events,
>  __bpf_kfunc_end_defs();
>  
>  BTF_KFUNCS_START(scx_kfunc_ids_any)
> +BTF_ID_FLAGS(func, scx_bpf_task_set_slice, KF_RCU);
> +BTF_ID_FLAGS(func, scx_bpf_task_set_dsq_vtime, KF_RCU);
>  BTF_ID_FLAGS(func, scx_bpf_kick_cpu)
>  BTF_ID_FLAGS(func, scx_bpf_dsq_nr_queued)
>  BTF_ID_FLAGS(func, scx_bpf_destroy_dsq)
> diff --git a/tools/sched_ext/include/scx/common.bpf.h b/tools/sched_ext/include/scx/common.bpf.h
> index 06e2551033cb..505231b7b7ae 100644
> --- a/tools/sched_ext/include/scx/common.bpf.h
> +++ b/tools/sched_ext/include/scx/common.bpf.h
> @@ -102,6 +102,8 @@ s32 scx_bpf_pick_any_cpu_node(const cpumask_t *cpus_allowed, int node, u64 flags
>  s32 scx_bpf_pick_any_cpu(const cpumask_t *cpus_allowed, u64 flags) __ksym;
>  bool scx_bpf_task_running(const struct task_struct *p) __ksym;
>  s32 scx_bpf_task_cpu(const struct task_struct *p) __ksym;
> +bool scx_bpf_task_set_slice(struct task_struct *p, u64 slice) __ksym __weak;
> +bool scx_bpf_task_set_dsq_vtime(struct task_struct *p, u64 vtime) __ksym __weak;
>  struct rq *scx_bpf_cpu_rq(s32 cpu) __ksym;
>  struct rq *scx_bpf_locked_rq(void) __ksym;
>  struct task_struct *scx_bpf_cpu_curr(s32 cpu) __ksym __weak;
> -- 
> 2.51.0
> 

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 4/4] sched_ext: Make scx_bpf_dsq_insert*() return bool
  2025-10-07  1:51 ` [PATCH 4/4] sched_ext: Make scx_bpf_dsq_insert*() return bool Tejun Heo
  2025-10-07  4:28   ` Emil Tsalapatis
@ 2025-10-07  9:41   ` Andrea Righi
  2025-10-07 15:03     ` Emil Tsalapatis
  2025-10-07 16:47   ` Changwoo Min
  2 siblings, 1 reply; 26+ messages in thread
From: Andrea Righi @ 2025-10-07  9:41 UTC (permalink / raw)
  To: Tejun Heo; +Cc: David Vernet, Changwoo Min, linux-kernel, sched-ext

On Mon, Oct 06, 2025 at 03:51:47PM -1000, Tejun Heo wrote:
> In preparation for hierarchical schedulers, change scx_bpf_dsq_insert() and
> scx_bpf_dsq_insert_vtime() to return bool instead of void. With
> sub-schedulers, there will be no reliable way to guarantee a task is still
> owned by the sub-scheduler at insertion time (e.g., the task may have been
> migrated to another scheduler). The bool return value will enable
> sub-schedulers to detect and gracefully handle insertion failures.
> 
> For the root scheduler, insertion failures will continue to trigger scheduler
> abort via scx_error(), so existing code doesn't need to check the return
> value. Backward compatibility is maintained through compat wrappers.
> 
> Also update scx_bpf_dsq_move() documentation to clarify that it can return
> false for sub-schedulers when @dsq_id points to a disallowed local DSQ.
> 
> Signed-off-by: Tejun Heo <tj@kernel.org>
> ---

...

>  kernel/sched/ext.c                       | 45 ++++++++++++++++++------
>  tools/sched_ext/include/scx/common.bpf.h |  3 +-
>  tools/sched_ext/include/scx/compat.bpf.h | 23 ++++++++++--
>  3 files changed, 56 insertions(+), 15 deletions(-)
> 
> diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c
> index a34e731229de..399e53c8939c 100644
> --- a/kernel/sched/ext.c
> +++ b/kernel/sched/ext.c
> @@ -5323,8 +5323,12 @@ __bpf_kfunc_start_defs();
>   * exhaustion. If zero, the current residual slice is maintained. If
>   * %SCX_SLICE_INF, @p never expires and the BPF scheduler must kick the CPU with
>   * scx_bpf_kick_cpu() to trigger scheduling.
> + *
> + * Returns %true on successful insertion, %false on failure. On the root
> + * scheduler, %false return triggers scheduler abort and the caller doesn't need
> + * to check the return value.
>   */
> -__bpf_kfunc void scx_bpf_dsq_insert(struct task_struct *p, u64 dsq_id, u64 slice,
> +__bpf_kfunc bool scx_bpf_dsq_insert(struct task_struct *p, u64 dsq_id, u64 slice,
>  				    u64 enq_flags)
>  {
>  	struct scx_sched *sch;
> @@ -5332,10 +5336,10 @@ __bpf_kfunc void scx_bpf_dsq_insert(struct task_struct *p, u64 dsq_id, u64 slice
>  	guard(rcu)();
>  	sch = rcu_dereference(scx_root);
>  	if (unlikely(!sch))
> -		return;
> +		return false;
>  
>  	if (!scx_dsq_insert_preamble(sch, p, enq_flags))
> -		return;
> +		return false;
>  
>  	if (slice)
>  		p->scx.slice = slice;
> @@ -5343,13 +5347,24 @@ __bpf_kfunc void scx_bpf_dsq_insert(struct task_struct *p, u64 dsq_id, u64 slice
>  		p->scx.slice = p->scx.slice ?: 1;
>  
>  	scx_dsq_insert_commit(sch, p, dsq_id, enq_flags);
> +
> +	return true;
> +}
> +
> +/*
> + * COMPAT: Will be removed in v6.23.
> + */
> +__bpf_kfunc void scx_bpf_dsq_insert___compat(struct task_struct *p, u64 dsq_id,
> +					     u64 slice, u64 enq_flags)
> +{
> +	scx_bpf_dsq_insert(p, dsq_id, slice, enq_flags);
>  }
>  
> -static void scx_dsq_insert_vtime(struct scx_sched *sch, struct task_struct *p,
> +static bool scx_dsq_insert_vtime(struct scx_sched *sch, struct task_struct *p,
>  				 u64 dsq_id, u64 slice, u64 vtime, u64 enq_flags)
>  {
>  	if (!scx_dsq_insert_preamble(sch, p, enq_flags))
> -		return;
> +		return false;
>  
>  	if (slice)
>  		p->scx.slice = slice;
> @@ -5359,6 +5374,8 @@ static void scx_dsq_insert_vtime(struct scx_sched *sch, struct task_struct *p,
>  	p->scx.dsq_vtime = vtime;
>  
>  	scx_dsq_insert_commit(sch, p, dsq_id, enq_flags | SCX_ENQ_DSQ_PRIQ);
> +
> +	return true;
>  }
>  
>  struct scx_bpf_dsq_insert_vtime_args {
> @@ -5394,8 +5411,12 @@ struct scx_bpf_dsq_insert_vtime_args {
>   * function must not be called on a DSQ which already has one or more FIFO tasks
>   * queued and vice-versa. Also, the built-in DSQs (SCX_DSQ_LOCAL and
>   * SCX_DSQ_GLOBAL) cannot be used as priority queues.
> + *
> + * Returns %true on successful insertion, %false on failure. On the root
> + * scheduler, %false return triggers scheduler abort and the caller doesn't need
> + * to check the return value.
>   */
> -__bpf_kfunc void
> +__bpf_kfunc bool
>  __scx_bpf_dsq_insert_vtime(struct task_struct *p,
>  			   struct scx_bpf_dsq_insert_vtime_args *args)
>  {
> @@ -5405,10 +5426,10 @@ __scx_bpf_dsq_insert_vtime(struct task_struct *p,
>  
>  	sch = rcu_dereference(scx_root);
>  	if (unlikely(!sch))
> -		return;
> +		return false;
>  
> -	scx_dsq_insert_vtime(sch, p, args->dsq_id, args->slice, args->vtime,
> -			     args->enq_flags);
> +	return scx_dsq_insert_vtime(sch, p, args->dsq_id, args->slice,
> +				    args->vtime, args->enq_flags);
>  }
>  
>  /*
> @@ -5432,6 +5453,7 @@ __bpf_kfunc_end_defs();
>  
>  BTF_KFUNCS_START(scx_kfunc_ids_enqueue_dispatch)
>  BTF_ID_FLAGS(func, scx_bpf_dsq_insert, KF_RCU)
> +BTF_ID_FLAGS(func, scx_bpf_dsq_insert___compat, KF_RCU)
>  BTF_ID_FLAGS(func, __scx_bpf_dsq_insert_vtime, KF_RCU)
>  BTF_ID_FLAGS(func, scx_bpf_dsq_insert_vtime, KF_RCU)
>  BTF_KFUNCS_END(scx_kfunc_ids_enqueue_dispatch)
> @@ -5686,8 +5708,9 @@ __bpf_kfunc void scx_bpf_dsq_move_set_vtime(struct bpf_iter_scx_dsq *it__iter,
>   * Can be called from ops.dispatch() or any BPF context which doesn't hold a rq
>   * lock (e.g. BPF timers or SYSCALL programs).
>   *
> - * Returns %true if @p has been consumed, %false if @p had already been consumed
> - * or dequeued.
> + * Returns %true if @p has been consumed, %false if @p had already been
> + * consumed, dequeued, or, for sub-scheds, @dsq_id points to a disallowed local
> + * DSQ.
>   */
>  __bpf_kfunc bool scx_bpf_dsq_move(struct bpf_iter_scx_dsq *it__iter,
>  				  struct task_struct *p, u64 dsq_id,
> diff --git a/tools/sched_ext/include/scx/common.bpf.h b/tools/sched_ext/include/scx/common.bpf.h
> index b1c2a0dde76e..522c90d0ced2 100644
> --- a/tools/sched_ext/include/scx/common.bpf.h
> +++ b/tools/sched_ext/include/scx/common.bpf.h
> @@ -62,8 +62,7 @@ s32 scx_bpf_create_dsq(u64 dsq_id, s32 node) __ksym;
>  s32 scx_bpf_select_cpu_dfl(struct task_struct *p, s32 prev_cpu, u64 wake_flags, bool *is_idle) __ksym;
>  s32 __scx_bpf_select_cpu_and(struct task_struct *p, const struct cpumask *cpus_allowed,
>  			     struct scx_bpf_select_cpu_and_args *args) __ksym __weak;
> -void scx_bpf_dsq_insert(struct task_struct *p, u64 dsq_id, u64 slice, u64 enq_flags) __ksym __weak;
> -void __scx_bpf_dsq_insert_vtime(struct task_struct *p, struct scx_bpf_dsq_insert_vtime_args *args) __ksym __weak;
> +bool __scx_bpf_dsq_insert_vtime(struct task_struct *p, struct scx_bpf_dsq_insert_vtime_args *args) __ksym __weak;
>  u32 scx_bpf_dispatch_nr_slots(void) __ksym;
>  void scx_bpf_dispatch_cancel(void) __ksym;
>  bool scx_bpf_dsq_move_to_local(u64 dsq_id) __ksym __weak;
> diff --git a/tools/sched_ext/include/scx/compat.bpf.h b/tools/sched_ext/include/scx/compat.bpf.h
> index e172de696f99..33c26928f4e9 100644
> --- a/tools/sched_ext/include/scx/compat.bpf.h
> +++ b/tools/sched_ext/include/scx/compat.bpf.h
> @@ -196,7 +196,7 @@ scx_bpf_select_cpu_and(struct task_struct *p, s32 prev_cpu, u64 wake_flags,
>   * Inline wrapper that packs scalar arguments into a struct and calls
>   * __scx_bpf_dsq_insert_vtime(). See __scx_bpf_dsq_insert_vtime() for details.
>   */
> -static inline void
> +static inline bool
>  scx_bpf_dsq_insert_vtime(struct task_struct *p, u64 dsq_id, u64 slice, u64 vtime,
>  			 u64 enq_flags)
>  {
> @@ -208,10 +208,29 @@ scx_bpf_dsq_insert_vtime(struct task_struct *p, u64 dsq_id, u64 slice, u64 vtime
>  			.enq_flags = enq_flags,
>  		};
>  
> -		__scx_bpf_dsq_insert_vtime(p, &args);
> +		return __scx_bpf_dsq_insert_vtime(p, &args);
>  	} else {
>  		scx_bpf_dsq_insert_vtime___compat(p, dsq_id, slice, vtime,
>  						  enq_flags);
> +		return true;
> +	}
> +}
> +
> +/*
> + * v6.19: scx_bpf_dsq_insert() now returns bool instead of void. Move
> + * scx_bpf_dsq_insert() decl to common.bpf.h and drop compat helper after v6.22.
> + */
> +bool scx_bpf_dsq_insert___new(struct task_struct *p, u64 dsq_id, u64 slice, u64 enq_flags) __ksym __weak;
> +void scx_bpf_dsq_insert___compat(struct task_struct *p, u64 dsq_id, u64 slice, u64 enq_flags) __ksym __weak;
> +
> +static inline bool
> +scx_bpf_dsq_insert(struct task_struct *p, u64 dsq_id, u64 slice, u64 enq_flags)
> +{
> +	if (bpf_ksym_exists(scx_bpf_dsq_insert___new)) {

I'm confused... where is scx_bpf_dsq_insert___new() defined?

> +		return scx_bpf_dsq_insert___new(p, dsq_id, slice, enq_flags);
> +	} else {
> +		scx_bpf_dsq_insert___compat(p, dsq_id, slice, enq_flags);
> +		return true;
>  	}
>  }
>  
> -- 
> 2.51.0
> 

Thanks,
-Andrea

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 1/4] tools/sched_ext: Strip compatibility macros for cgroup and dispatch APIs
  2025-10-07  1:51 ` [PATCH 1/4] tools/sched_ext: Strip compatibility macros for cgroup and dispatch APIs Tejun Heo
  2025-10-07  2:42   ` Emil Tsalapatis
@ 2025-10-07  9:42   ` Andrea Righi
  2025-10-07 16:22   ` Changwoo Min
  2 siblings, 0 replies; 26+ messages in thread
From: Andrea Righi @ 2025-10-07  9:42 UTC (permalink / raw)
  To: Tejun Heo; +Cc: David Vernet, Changwoo Min, linux-kernel, sched-ext

On Mon, Oct 06, 2025 at 03:51:44PM -1000, Tejun Heo wrote:
> Enough time has passed since the introduction of scx_bpf_task_cgroup() and
> the scx_bpf_dispatch* -> scx_bpf_dsq* kfunc renaming. Strip the compatibility
> macros.
> 
> Signed-off-by: Tejun Heo <tj@kernel.org>

Acked-by: Andrea Righi <arighi@nvidia.com>

Thanks,
-Andrea

> ---
>  tools/sched_ext/include/scx/compat.bpf.h | 108 +----------------------
>  tools/sched_ext/scx_flatcg.bpf.c         |  10 +--
>  tools/sched_ext/scx_qmap.bpf.c           |  14 ++-
>  3 files changed, 12 insertions(+), 120 deletions(-)
> 
> diff --git a/tools/sched_ext/include/scx/compat.bpf.h b/tools/sched_ext/include/scx/compat.bpf.h
> index dd9144624dc9..d979f16a3ae2 100644
> --- a/tools/sched_ext/include/scx/compat.bpf.h
> +++ b/tools/sched_ext/include/scx/compat.bpf.h
> @@ -15,121 +15,17 @@
>  	__ret;									\
>  })
>  
> -/* v6.12: 819513666966 ("sched_ext: Add cgroup support") */
> -#define __COMPAT_scx_bpf_task_cgroup(p)						\
> -	(bpf_ksym_exists(scx_bpf_task_cgroup) ?					\
> -	 scx_bpf_task_cgroup((p)) : NULL)
> -
>  /*
> - * v6.13: The verb `dispatch` was too overloaded and confusing. kfuncs are
> - * renamed to unload the verb.
> - *
> - * Build error is triggered if old names are used. New binaries work with both
> - * new and old names. The compat macros will be removed on v6.15 release.
> + * v6.15: 950ad93df2fc ("bpf: add kfunc for populating cpumask bits")
>   *
> - * scx_bpf_dispatch_from_dsq() and friends were added during v6.12 by
> - * 4c30f5ce4f7a ("sched_ext: Implement scx_bpf_dispatch[_vtime]_from_dsq()").
> - * Preserve __COMPAT macros until v6.15.
> + * Compat macro will be dropped on v6.19 release.
>   */
> -void scx_bpf_dispatch___compat(struct task_struct *p, u64 dsq_id, u64 slice, u64 enq_flags) __ksym __weak;
> -void scx_bpf_dispatch_vtime___compat(struct task_struct *p, u64 dsq_id, u64 slice, u64 vtime, u64 enq_flags) __ksym __weak;
> -bool scx_bpf_consume___compat(u64 dsq_id) __ksym __weak;
> -void scx_bpf_dispatch_from_dsq_set_slice___compat(struct bpf_iter_scx_dsq *it__iter, u64 slice) __ksym __weak;
> -void scx_bpf_dispatch_from_dsq_set_vtime___compat(struct bpf_iter_scx_dsq *it__iter, u64 vtime) __ksym __weak;
> -bool scx_bpf_dispatch_from_dsq___compat(struct bpf_iter_scx_dsq *it__iter, struct task_struct *p, u64 dsq_id, u64 enq_flags) __ksym __weak;
> -bool scx_bpf_dispatch_vtime_from_dsq___compat(struct bpf_iter_scx_dsq *it__iter, struct task_struct *p, u64 dsq_id, u64 enq_flags) __ksym __weak;
>  int bpf_cpumask_populate(struct cpumask *dst, void *src, size_t src__sz) __ksym __weak;
>  
> -#define scx_bpf_dsq_insert(p, dsq_id, slice, enq_flags)				\
> -	(bpf_ksym_exists(scx_bpf_dsq_insert) ?					\
> -	 scx_bpf_dsq_insert((p), (dsq_id), (slice), (enq_flags)) :		\
> -	 scx_bpf_dispatch___compat((p), (dsq_id), (slice), (enq_flags)))
> -
> -#define scx_bpf_dsq_insert_vtime(p, dsq_id, slice, vtime, enq_flags)		\
> -	(bpf_ksym_exists(scx_bpf_dsq_insert_vtime) ?				\
> -	 scx_bpf_dsq_insert_vtime((p), (dsq_id), (slice), (vtime), (enq_flags)) : \
> -	 scx_bpf_dispatch_vtime___compat((p), (dsq_id), (slice), (vtime), (enq_flags)))
> -
> -#define scx_bpf_dsq_move_to_local(dsq_id)					\
> -	(bpf_ksym_exists(scx_bpf_dsq_move_to_local) ?				\
> -	 scx_bpf_dsq_move_to_local((dsq_id)) :					\
> -	 scx_bpf_consume___compat((dsq_id)))
> -
> -#define __COMPAT_scx_bpf_dsq_move_set_slice(it__iter, slice)			\
> -	(bpf_ksym_exists(scx_bpf_dsq_move_set_slice) ?				\
> -	 scx_bpf_dsq_move_set_slice((it__iter), (slice)) :			\
> -	 (bpf_ksym_exists(scx_bpf_dispatch_from_dsq_set_slice___compat) ?	\
> -	  scx_bpf_dispatch_from_dsq_set_slice___compat((it__iter), (slice)) :	\
> -	  (void)0))
> -
> -#define __COMPAT_scx_bpf_dsq_move_set_vtime(it__iter, vtime)			\
> -	(bpf_ksym_exists(scx_bpf_dsq_move_set_vtime) ?				\
> -	 scx_bpf_dsq_move_set_vtime((it__iter), (vtime)) :			\
> -	 (bpf_ksym_exists(scx_bpf_dispatch_from_dsq_set_vtime___compat) ?	\
> -	  scx_bpf_dispatch_from_dsq_set_vtime___compat((it__iter), (vtime)) :	\
> -	  (void) 0))
> -
> -#define __COMPAT_scx_bpf_dsq_move(it__iter, p, dsq_id, enq_flags)		\
> -	(bpf_ksym_exists(scx_bpf_dsq_move) ?					\
> -	 scx_bpf_dsq_move((it__iter), (p), (dsq_id), (enq_flags)) :		\
> -	 (bpf_ksym_exists(scx_bpf_dispatch_from_dsq___compat) ?			\
> -	  scx_bpf_dispatch_from_dsq___compat((it__iter), (p), (dsq_id), (enq_flags)) : \
> -	  false))
> -
> -#define __COMPAT_scx_bpf_dsq_move_vtime(it__iter, p, dsq_id, enq_flags)		\
> -	(bpf_ksym_exists(scx_bpf_dsq_move_vtime) ?				\
> -	 scx_bpf_dsq_move_vtime((it__iter), (p), (dsq_id), (enq_flags)) :	\
> -	 (bpf_ksym_exists(scx_bpf_dispatch_vtime_from_dsq___compat) ?		\
> -	  scx_bpf_dispatch_vtime_from_dsq___compat((it__iter), (p), (dsq_id), (enq_flags)) : \
> -	  false))
> -
>  #define __COMPAT_bpf_cpumask_populate(cpumask, src, size__sz)		\
>  	(bpf_ksym_exists(bpf_cpumask_populate) ?			\
>  	 (bpf_cpumask_populate(cpumask, src, size__sz)) : -EOPNOTSUPP)
>  
> -#define scx_bpf_dispatch(p, dsq_id, slice, enq_flags)				\
> -	_Static_assert(false, "scx_bpf_dispatch() renamed to scx_bpf_dsq_insert()")
> -
> -#define scx_bpf_dispatch_vtime(p, dsq_id, slice, vtime, enq_flags)		\
> -	_Static_assert(false, "scx_bpf_dispatch_vtime() renamed to scx_bpf_dsq_insert_vtime()")
> -
> -#define scx_bpf_consume(dsq_id) ({						\
> -	_Static_assert(false, "scx_bpf_consume() renamed to scx_bpf_dsq_move_to_local()"); \
> -	false;									\
> -})
> -
> -#define scx_bpf_dispatch_from_dsq_set_slice(it__iter, slice)		\
> -	_Static_assert(false, "scx_bpf_dispatch_from_dsq_set_slice() renamed to scx_bpf_dsq_move_set_slice()")
> -
> -#define scx_bpf_dispatch_from_dsq_set_vtime(it__iter, vtime)		\
> -	_Static_assert(false, "scx_bpf_dispatch_from_dsq_set_vtime() renamed to scx_bpf_dsq_move_set_vtime()")
> -
> -#define scx_bpf_dispatch_from_dsq(it__iter, p, dsq_id, enq_flags) ({	\
> -	_Static_assert(false, "scx_bpf_dispatch_from_dsq() renamed to scx_bpf_dsq_move()"); \
> -	false;									\
> -})
> -
> -#define scx_bpf_dispatch_vtime_from_dsq(it__iter, p, dsq_id, enq_flags) ({  \
> -	_Static_assert(false, "scx_bpf_dispatch_vtime_from_dsq() renamed to scx_bpf_dsq_move_vtime()"); \
> -	false;									\
> -})
> -
> -#define __COMPAT_scx_bpf_dispatch_from_dsq_set_slice(it__iter, slice)		\
> -	_Static_assert(false, "__COMPAT_scx_bpf_dispatch_from_dsq_set_slice() renamed to __COMPAT_scx_bpf_dsq_move_set_slice()")
> -
> -#define __COMPAT_scx_bpf_dispatch_from_dsq_set_vtime(it__iter, vtime)		\
> -	_Static_assert(false, "__COMPAT_scx_bpf_dispatch_from_dsq_set_vtime() renamed to __COMPAT_scx_bpf_dsq_move_set_vtime()")
> -
> -#define __COMPAT_scx_bpf_dispatch_from_dsq(it__iter, p, dsq_id, enq_flags) ({	\
> -	_Static_assert(false, "__COMPAT_scx_bpf_dispatch_from_dsq() renamed to __COMPAT_scx_bpf_dsq_move()"); \
> -	false;									\
> -})
> -
> -#define __COMPAT_scx_bpf_dispatch_vtime_from_dsq(it__iter, p, dsq_id, enq_flags) ({  \
> -	_Static_assert(false, "__COMPAT_scx_bpf_dispatch_vtime_from_dsq() renamed to __COMPAT_scx_bpf_dsq_move_vtime()"); \
> -	false;									\
> -})
> -
>  /**
>   * __COMPAT_is_enq_cpu_selected - Test if SCX_ENQ_CPU_SELECTED is on
>   * in a compatible way. We will preserve this __COMPAT helper until v6.16.
> diff --git a/tools/sched_ext/scx_flatcg.bpf.c b/tools/sched_ext/scx_flatcg.bpf.c
> index 2c720e3ecad5..43126858b8e4 100644
> --- a/tools/sched_ext/scx_flatcg.bpf.c
> +++ b/tools/sched_ext/scx_flatcg.bpf.c
> @@ -382,7 +382,7 @@ void BPF_STRUCT_OPS(fcg_enqueue, struct task_struct *p, u64 enq_flags)
>  		return;
>  	}
>  
> -	cgrp = __COMPAT_scx_bpf_task_cgroup(p);
> +	cgrp = scx_bpf_task_cgroup(p);
>  	cgc = find_cgrp_ctx(cgrp);
>  	if (!cgc)
>  		goto out_release;
> @@ -508,7 +508,7 @@ void BPF_STRUCT_OPS(fcg_runnable, struct task_struct *p, u64 enq_flags)
>  {
>  	struct cgroup *cgrp;
>  
> -	cgrp = __COMPAT_scx_bpf_task_cgroup(p);
> +	cgrp = scx_bpf_task_cgroup(p);
>  	update_active_weight_sums(cgrp, true);
>  	bpf_cgroup_release(cgrp);
>  }
> @@ -521,7 +521,7 @@ void BPF_STRUCT_OPS(fcg_running, struct task_struct *p)
>  	if (fifo_sched)
>  		return;
>  
> -	cgrp = __COMPAT_scx_bpf_task_cgroup(p);
> +	cgrp = scx_bpf_task_cgroup(p);
>  	cgc = find_cgrp_ctx(cgrp);
>  	if (cgc) {
>  		/*
> @@ -564,7 +564,7 @@ void BPF_STRUCT_OPS(fcg_stopping, struct task_struct *p, bool runnable)
>  	if (!taskc->bypassed_at)
>  		return;
>  
> -	cgrp = __COMPAT_scx_bpf_task_cgroup(p);
> +	cgrp = scx_bpf_task_cgroup(p);
>  	cgc = find_cgrp_ctx(cgrp);
>  	if (cgc) {
>  		__sync_fetch_and_add(&cgc->cvtime_delta,
> @@ -578,7 +578,7 @@ void BPF_STRUCT_OPS(fcg_quiescent, struct task_struct *p, u64 deq_flags)
>  {
>  	struct cgroup *cgrp;
>  
> -	cgrp = __COMPAT_scx_bpf_task_cgroup(p);
> +	cgrp = scx_bpf_task_cgroup(p);
>  	update_active_weight_sums(cgrp, false);
>  	bpf_cgroup_release(cgrp);
>  }
> diff --git a/tools/sched_ext/scx_qmap.bpf.c b/tools/sched_ext/scx_qmap.bpf.c
> index 3072b593f898..c67dac78a4c6 100644
> --- a/tools/sched_ext/scx_qmap.bpf.c
> +++ b/tools/sched_ext/scx_qmap.bpf.c
> @@ -320,12 +320,9 @@ static bool dispatch_highpri(bool from_timer)
>  
>  		if (tctx->highpri) {
>  			/* exercise the set_*() and vtime interface too */
> -			__COMPAT_scx_bpf_dsq_move_set_slice(
> -				BPF_FOR_EACH_ITER, slice_ns * 2);
> -			__COMPAT_scx_bpf_dsq_move_set_vtime(
> -				BPF_FOR_EACH_ITER, highpri_seq++);
> -			__COMPAT_scx_bpf_dsq_move_vtime(
> -				BPF_FOR_EACH_ITER, p, HIGHPRI_DSQ, 0);
> +			scx_bpf_dsq_move_set_slice(BPF_FOR_EACH_ITER, slice_ns * 2);
> +			scx_bpf_dsq_move_set_vtime(BPF_FOR_EACH_ITER, highpri_seq++);
> +			scx_bpf_dsq_move_vtime(BPF_FOR_EACH_ITER, p, HIGHPRI_DSQ, 0);
>  		}
>  	}
>  
> @@ -342,9 +339,8 @@ static bool dispatch_highpri(bool from_timer)
>  		else
>  			cpu = scx_bpf_pick_any_cpu(p->cpus_ptr, 0);
>  
> -		if (__COMPAT_scx_bpf_dsq_move(BPF_FOR_EACH_ITER, p,
> -					      SCX_DSQ_LOCAL_ON | cpu,
> -					      SCX_ENQ_PREEMPT)) {
> +		if (scx_bpf_dsq_move(BPF_FOR_EACH_ITER, p, SCX_DSQ_LOCAL_ON | cpu,
> +				     SCX_ENQ_PREEMPT)) {
>  			if (cpu == this_cpu) {
>  				dispatched = true;
>  				__sync_fetch_and_add(&nr_expedited_local, 1);
> -- 
> 2.51.0
> 

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 3/4] sched_ext: Wrap kfunc args in struct to prepare for aux__prog
  2025-10-07  1:51 ` [PATCH 3/4] sched_ext: Wrap kfunc args in struct to prepare for aux__prog Tejun Heo
@ 2025-10-07  9:48   ` Andrea Righi
  2025-10-07 18:24     ` Tejun Heo
  2025-10-07 16:04   ` Emil Tsalapatis
  2025-10-07 16:38   ` Changwoo Min
  2 siblings, 1 reply; 26+ messages in thread
From: Andrea Righi @ 2025-10-07  9:48 UTC (permalink / raw)
  To: Tejun Heo; +Cc: David Vernet, Changwoo Min, linux-kernel, sched-ext

Hi Tejun,

On Mon, Oct 06, 2025 at 03:51:46PM -1000, Tejun Heo wrote:
> scx_bpf_dsq_insert_vtime() and scx_bpf_select_cpu_and() currently have 5
> parameters. An upcoming change will add aux__prog parameter which will exceed
> BPF's 5 argument limit.
> 
> Prepare by adding new kfuncs __scx_bpf_dsq_insert_vtime() and
> __scx_bpf_select_cpu_and() that take args structs. The existing kfuncs are
> kept as compatibility wrappers. BPF programs use inline wrappers that detect
> kernel API version via bpf_core_type_exists() and use the new struct-based
> kfuncs when available, falling back to compat kfuncs otherwise. This allows
> BPF programs to work with both old and new kernels.
> 
> Signed-off-by: Tejun Heo <tj@kernel.org>
> ---
>  kernel/sched/ext.c                       | 82 ++++++++++++++++++------
>  kernel/sched/ext_idle.c                  | 43 +++++++++++--
>  tools/sched_ext/include/scx/common.bpf.h |  6 +-
>  tools/sched_ext/include/scx/compat.bpf.h | 72 +++++++++++++++++++++
>  4 files changed, 173 insertions(+), 30 deletions(-)
> 
> diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c
> index 6d76efaaa9b2..a34e731229de 100644
> --- a/kernel/sched/ext.c
> +++ b/kernel/sched/ext.c
> @@ -5345,54 +5345,94 @@ __bpf_kfunc void scx_bpf_dsq_insert(struct task_struct *p, u64 dsq_id, u64 slice
>  	scx_dsq_insert_commit(sch, p, dsq_id, enq_flags);
>  }
>  
> +static void scx_dsq_insert_vtime(struct scx_sched *sch, struct task_struct *p,
> +				 u64 dsq_id, u64 slice, u64 vtime, u64 enq_flags)
> +{
> +	if (!scx_dsq_insert_preamble(sch, p, enq_flags))
> +		return;
> +
> +	if (slice)
> +		p->scx.slice = slice;
> +	else
> +		p->scx.slice = p->scx.slice ?: 1;
> +
> +	p->scx.dsq_vtime = vtime;
> +
> +	scx_dsq_insert_commit(sch, p, dsq_id, enq_flags | SCX_ENQ_DSQ_PRIQ);
> +}
> +
> +struct scx_bpf_dsq_insert_vtime_args {
> +	/* @p can't be packed together as KF_RCU is not transitive */
> +	u64			dsq_id;
> +	u64			slice;
> +	u64			vtime;
> +	u64			enq_flags;
> +};

With PATCH 2/4 introducing scx_bpf_task_set_slice() and
scx_bpf_task_set_dsq_vtime(), would it be reasonable to use those to set
these task properties and then completely get rid of these args in
scx_bpf_dsq_insert[_vtime]()?

> +
>  /**
> - * scx_bpf_dsq_insert_vtime - Insert a task into the vtime priority queue of a DSQ
> + * __scx_bpf_dsq_insert_vtime - Arg-wrapped vtime DSQ insertion
>   * @p: task_struct to insert
> - * @dsq_id: DSQ to insert into
> - * @slice: duration @p can run for in nsecs, 0 to keep the current value
> - * @vtime: @p's ordering inside the vtime-sorted queue of the target DSQ
> - * @enq_flags: SCX_ENQ_*
> + * @args: struct containing the rest of the arguments
> + *       @args->dsq_id: DSQ to insert into
> + *       @args->slice: duration @p can run for in nsecs, 0 to keep the current value
> + *       @args->vtime: @p's ordering inside the vtime-sorted queue of the target DSQ
> + *       @args->enq_flags: SCX_ENQ_*
>   *
> - * Insert @p into the vtime priority queue of the DSQ identified by @dsq_id.
> - * Tasks queued into the priority queue are ordered by @vtime. All other aspects
> - * are identical to scx_bpf_dsq_insert().
> + * Wrapper kfunc that takes arguments via struct to work around BPF's 5 argument
> + * limit. BPF programs should use scx_bpf_dsq_insert_vtime() which is provided
> + * as an inline wrapper in common.bpf.h.
>   *
> - * @vtime ordering is according to time_before64() which considers wrapping. A
> - * numerically larger vtime may indicate an earlier position in the ordering and
> - * vice-versa.
> + * Insert @p into the vtime priority queue of the DSQ identified by
> + * @args->dsq_id. Tasks queued into the priority queue are ordered by
> + * @args->vtime. All other aspects are identical to scx_bpf_dsq_insert().
> + *
> + * @args->vtime ordering is according to time_before64() which considers
> + * wrapping. A numerically larger vtime may indicate an earlier position in the
> + * ordering and vice-versa.
>   *
>   * A DSQ can only be used as a FIFO or priority queue at any given time and this
>   * function must not be called on a DSQ which already has one or more FIFO tasks
>   * queued and vice-versa. Also, the built-in DSQs (SCX_DSQ_LOCAL and
>   * SCX_DSQ_GLOBAL) cannot be used as priority queues.
>   */
> -__bpf_kfunc void scx_bpf_dsq_insert_vtime(struct task_struct *p, u64 dsq_id,
> -					  u64 slice, u64 vtime, u64 enq_flags)
> +__bpf_kfunc void
> +__scx_bpf_dsq_insert_vtime(struct task_struct *p,
> +			   struct scx_bpf_dsq_insert_vtime_args *args)
>  {
>  	struct scx_sched *sch;
>  
>  	guard(rcu)();
> +
>  	sch = rcu_dereference(scx_root);
>  	if (unlikely(!sch))
>  		return;
>  
> -	if (!scx_dsq_insert_preamble(sch, p, enq_flags))
> -		return;
> +	scx_dsq_insert_vtime(sch, p, args->dsq_id, args->slice, args->vtime,
> +			     args->enq_flags);
> +}
>  
> -	if (slice)
> -		p->scx.slice = slice;
> -	else
> -		p->scx.slice = p->scx.slice ?: 1;
> +/*
> + * COMPAT: Will be removed in v6.23.
> + */
> +__bpf_kfunc void scx_bpf_dsq_insert_vtime(struct task_struct *p, u64 dsq_id,
> +					  u64 slice, u64 vtime, u64 enq_flags)
> +{
> +	struct scx_sched *sch;
>  
> -	p->scx.dsq_vtime = vtime;
> +	guard(rcu)();
>  
> -	scx_dsq_insert_commit(sch, p, dsq_id, enq_flags | SCX_ENQ_DSQ_PRIQ);
> +	sch = rcu_dereference(scx_root);
> +	if (unlikely(!sch))
> +		return;
> +
> +	scx_dsq_insert_vtime(sch, p, dsq_id, slice, vtime, enq_flags);
>  }
>  
>  __bpf_kfunc_end_defs();
>  
>  BTF_KFUNCS_START(scx_kfunc_ids_enqueue_dispatch)
>  BTF_ID_FLAGS(func, scx_bpf_dsq_insert, KF_RCU)
> +BTF_ID_FLAGS(func, __scx_bpf_dsq_insert_vtime, KF_RCU)
>  BTF_ID_FLAGS(func, scx_bpf_dsq_insert_vtime, KF_RCU)
>  BTF_KFUNCS_END(scx_kfunc_ids_enqueue_dispatch)
>  
> diff --git a/kernel/sched/ext_idle.c b/kernel/sched/ext_idle.c
> index d2434c954848..3d9d404d5cd2 100644
> --- a/kernel/sched/ext_idle.c
> +++ b/kernel/sched/ext_idle.c
> @@ -995,26 +995,56 @@ __bpf_kfunc s32 scx_bpf_select_cpu_dfl(struct task_struct *p, s32 prev_cpu,
>  	return prev_cpu;
>  }
>  
> +struct scx_bpf_select_cpu_and_args {
> +	/* @p and @cpus_allowed can't be packed together as KF_RCU is not transitive */
> +	s32			prev_cpu;
> +	u64			wake_flags;
> +	u64			flags;
> +};

And for this one, would it make sense to pack flags and wake_flags in a
single u64?

Thanks,
-Andrea

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 4/4] sched_ext: Make scx_bpf_dsq_insert*() return bool
  2025-10-07  9:41   ` Andrea Righi
@ 2025-10-07 15:03     ` Emil Tsalapatis
  2025-10-07 17:25       ` Andrea Righi
  0 siblings, 1 reply; 26+ messages in thread
From: Emil Tsalapatis @ 2025-10-07 15:03 UTC (permalink / raw)
  To: Andrea Righi
  Cc: Tejun Heo, David Vernet, Changwoo Min, linux-kernel, sched-ext

On Tue, Oct 7, 2025 at 5:41 AM Andrea Righi <arighi@nvidia.com> wrote:
>
> On Mon, Oct 06, 2025 at 03:51:47PM -1000, Tejun Heo wrote:
> > In preparation for hierarchical schedulers, change scx_bpf_dsq_insert() and
> > scx_bpf_dsq_insert_vtime() to return bool instead of void. With
> > sub-schedulers, there will be no reliable way to guarantee a task is still
> > owned by the sub-scheduler at insertion time (e.g., the task may have been
> > migrated to another scheduler). The bool return value will enable
> > sub-schedulers to detect and gracefully handle insertion failures.
> >
> > For the root scheduler, insertion failures will continue to trigger scheduler
> > abort via scx_error(), so existing code doesn't need to check the return
> > value. Backward compatibility is maintained through compat wrappers.
> >
> > Also update scx_bpf_dsq_move() documentation to clarify that it can return
> > false for sub-schedulers when @dsq_id points to a disallowed local DSQ.
> >
> > Signed-off-by: Tejun Heo <tj@kernel.org>
> > ---
>
> ...
>
> >  kernel/sched/ext.c                       | 45 ++++++++++++++++++------
> >  tools/sched_ext/include/scx/common.bpf.h |  3 +-
> >  tools/sched_ext/include/scx/compat.bpf.h | 23 ++++++++++--
> >  3 files changed, 56 insertions(+), 15 deletions(-)
> >
> > diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c
> > index a34e731229de..399e53c8939c 100644
> > --- a/kernel/sched/ext.c
> > +++ b/kernel/sched/ext.c
> > @@ -5323,8 +5323,12 @@ __bpf_kfunc_start_defs();
> >   * exhaustion. If zero, the current residual slice is maintained. If
> >   * %SCX_SLICE_INF, @p never expires and the BPF scheduler must kick the CPU with
> >   * scx_bpf_kick_cpu() to trigger scheduling.
> > + *
> > + * Returns %true on successful insertion, %false on failure. On the root
> > + * scheduler, %false return triggers scheduler abort and the caller doesn't need
> > + * to check the return value.
> >   */
> > -__bpf_kfunc void scx_bpf_dsq_insert(struct task_struct *p, u64 dsq_id, u64 slice,
> > +__bpf_kfunc bool scx_bpf_dsq_insert(struct task_struct *p, u64 dsq_id, u64 slice,
> >                                   u64 enq_flags)
> >  {
> >       struct scx_sched *sch;
> > @@ -5332,10 +5336,10 @@ __bpf_kfunc void scx_bpf_dsq_insert(struct task_struct *p, u64 dsq_id, u64 slice
> >       guard(rcu)();
> >       sch = rcu_dereference(scx_root);
> >       if (unlikely(!sch))
> > -             return;
> > +             return false;
> >
> >       if (!scx_dsq_insert_preamble(sch, p, enq_flags))
> > -             return;
> > +             return false;
> >
> >       if (slice)
> >               p->scx.slice = slice;
> > @@ -5343,13 +5347,24 @@ __bpf_kfunc void scx_bpf_dsq_insert(struct task_struct *p, u64 dsq_id, u64 slice
> >               p->scx.slice = p->scx.slice ?: 1;
> >
> >       scx_dsq_insert_commit(sch, p, dsq_id, enq_flags);
> > +
> > +     return true;
> > +}
> > +
> > +/*
> > + * COMPAT: Will be removed in v6.23.
> > + */
> > +__bpf_kfunc void scx_bpf_dsq_insert___compat(struct task_struct *p, u64 dsq_id,
> > +                                          u64 slice, u64 enq_flags)
> > +{
> > +     scx_bpf_dsq_insert(p, dsq_id, slice, enq_flags);
> >  }
> >
> > -static void scx_dsq_insert_vtime(struct scx_sched *sch, struct task_struct *p,
> > +static bool scx_dsq_insert_vtime(struct scx_sched *sch, struct task_struct *p,
> >                                u64 dsq_id, u64 slice, u64 vtime, u64 enq_flags)
> >  {
> >       if (!scx_dsq_insert_preamble(sch, p, enq_flags))
> > -             return;
> > +             return false;
> >
> >       if (slice)
> >               p->scx.slice = slice;
> > @@ -5359,6 +5374,8 @@ static void scx_dsq_insert_vtime(struct scx_sched *sch, struct task_struct *p,
> >       p->scx.dsq_vtime = vtime;
> >
> >       scx_dsq_insert_commit(sch, p, dsq_id, enq_flags | SCX_ENQ_DSQ_PRIQ);
> > +
> > +     return true;
> >  }
> >
> >  struct scx_bpf_dsq_insert_vtime_args {
> > @@ -5394,8 +5411,12 @@ struct scx_bpf_dsq_insert_vtime_args {
> >   * function must not be called on a DSQ which already has one or more FIFO tasks
> >   * queued and vice-versa. Also, the built-in DSQs (SCX_DSQ_LOCAL and
> >   * SCX_DSQ_GLOBAL) cannot be used as priority queues.
> > + *
> > + * Returns %true on successful insertion, %false on failure. On the root
> > + * scheduler, %false return triggers scheduler abort and the caller doesn't need
> > + * to check the return value.
> >   */
> > -__bpf_kfunc void
> > +__bpf_kfunc bool
> >  __scx_bpf_dsq_insert_vtime(struct task_struct *p,
> >                          struct scx_bpf_dsq_insert_vtime_args *args)
> >  {
> > @@ -5405,10 +5426,10 @@ __scx_bpf_dsq_insert_vtime(struct task_struct *p,
> >
> >       sch = rcu_dereference(scx_root);
> >       if (unlikely(!sch))
> > -             return;
> > +             return false;
> >
> > -     scx_dsq_insert_vtime(sch, p, args->dsq_id, args->slice, args->vtime,
> > -                          args->enq_flags);
> > +     return scx_dsq_insert_vtime(sch, p, args->dsq_id, args->slice,
> > +                                 args->vtime, args->enq_flags);
> >  }
> >
> >  /*
> > @@ -5432,6 +5453,7 @@ __bpf_kfunc_end_defs();
> >
> >  BTF_KFUNCS_START(scx_kfunc_ids_enqueue_dispatch)
> >  BTF_ID_FLAGS(func, scx_bpf_dsq_insert, KF_RCU)
> > +BTF_ID_FLAGS(func, scx_bpf_dsq_insert___compat, KF_RCU)
> >  BTF_ID_FLAGS(func, __scx_bpf_dsq_insert_vtime, KF_RCU)
> >  BTF_ID_FLAGS(func, scx_bpf_dsq_insert_vtime, KF_RCU)
> >  BTF_KFUNCS_END(scx_kfunc_ids_enqueue_dispatch)
> > @@ -5686,8 +5708,9 @@ __bpf_kfunc void scx_bpf_dsq_move_set_vtime(struct bpf_iter_scx_dsq *it__iter,
> >   * Can be called from ops.dispatch() or any BPF context which doesn't hold a rq
> >   * lock (e.g. BPF timers or SYSCALL programs).
> >   *
> > - * Returns %true if @p has been consumed, %false if @p had already been consumed
> > - * or dequeued.
> > + * Returns %true if @p has been consumed, %false if @p had already been
> > + * consumed, dequeued, or, for sub-scheds, @dsq_id points to a disallowed local
> > + * DSQ.
> >   */
> >  __bpf_kfunc bool scx_bpf_dsq_move(struct bpf_iter_scx_dsq *it__iter,
> >                                 struct task_struct *p, u64 dsq_id,
> > diff --git a/tools/sched_ext/include/scx/common.bpf.h b/tools/sched_ext/include/scx/common.bpf.h
> > index b1c2a0dde76e..522c90d0ced2 100644
> > --- a/tools/sched_ext/include/scx/common.bpf.h
> > +++ b/tools/sched_ext/include/scx/common.bpf.h
> > @@ -62,8 +62,7 @@ s32 scx_bpf_create_dsq(u64 dsq_id, s32 node) __ksym;
> >  s32 scx_bpf_select_cpu_dfl(struct task_struct *p, s32 prev_cpu, u64 wake_flags, bool *is_idle) __ksym;
> >  s32 __scx_bpf_select_cpu_and(struct task_struct *p, const struct cpumask *cpus_allowed,
> >                            struct scx_bpf_select_cpu_and_args *args) __ksym __weak;
> > -void scx_bpf_dsq_insert(struct task_struct *p, u64 dsq_id, u64 slice, u64 enq_flags) __ksym __weak;
> > -void __scx_bpf_dsq_insert_vtime(struct task_struct *p, struct scx_bpf_dsq_insert_vtime_args *args) __ksym __weak;
> > +bool __scx_bpf_dsq_insert_vtime(struct task_struct *p, struct scx_bpf_dsq_insert_vtime_args *args) __ksym __weak;
> >  u32 scx_bpf_dispatch_nr_slots(void) __ksym;
> >  void scx_bpf_dispatch_cancel(void) __ksym;
> >  bool scx_bpf_dsq_move_to_local(u64 dsq_id) __ksym __weak;
> > diff --git a/tools/sched_ext/include/scx/compat.bpf.h b/tools/sched_ext/include/scx/compat.bpf.h
> > index e172de696f99..33c26928f4e9 100644
> > --- a/tools/sched_ext/include/scx/compat.bpf.h
> > +++ b/tools/sched_ext/include/scx/compat.bpf.h
> > @@ -196,7 +196,7 @@ scx_bpf_select_cpu_and(struct task_struct *p, s32 prev_cpu, u64 wake_flags,
> >   * Inline wrapper that packs scalar arguments into a struct and calls
> >   * __scx_bpf_dsq_insert_vtime(). See __scx_bpf_dsq_insert_vtime() for details.
> >   */
> > -static inline void
> > +static inline bool
> >  scx_bpf_dsq_insert_vtime(struct task_struct *p, u64 dsq_id, u64 slice, u64 vtime,
> >                        u64 enq_flags)
> >  {
> > @@ -208,10 +208,29 @@ scx_bpf_dsq_insert_vtime(struct task_struct *p, u64 dsq_id, u64 slice, u64 vtime
> >                       .enq_flags = enq_flags,
> >               };
> >
> > -             __scx_bpf_dsq_insert_vtime(p, &args);
> > +             return __scx_bpf_dsq_insert_vtime(p, &args);
> >       } else {
> >               scx_bpf_dsq_insert_vtime___compat(p, dsq_id, slice, vtime,
> >                                                 enq_flags);
> > +             return true;
> > +     }
> > +}
> > +
> > +/*
> > + * v6.19: scx_bpf_dsq_insert() now returns bool instead of void. Move
> > + * scx_bpf_dsq_insert() decl to common.bpf.h and drop compat helper after v6.22.
> > + */
> > +bool scx_bpf_dsq_insert___new(struct task_struct *p, u64 dsq_id, u64 slice, u64 enq_flags) __ksym __weak;
> > +void scx_bpf_dsq_insert___compat(struct task_struct *p, u64 dsq_id, u64 slice, u64 enq_flags) __ksym __weak;
> > +
> > +static inline bool
> > +scx_bpf_dsq_insert(struct task_struct *p, u64 dsq_id, u64 slice, u64 enq_flags)
> > +{
> > +     if (bpf_ksym_exists(scx_bpf_dsq_insert___new)) {
>
> I'm confused... where is scx_bpf_dsq_insert___new() defined?
>

CO:RE relocation ignores suffixes if there is no match, so
scx_bpf_dsq_insert___new() defaults to scx_bpf_dsq_insert() in systems
with this patch. When I tested it the symbol resolved to
scx_bpf_dsq_insert(). We're not really matching the name, we're
matching the signature and trying to find a kfunc with the the
scx_bpf_dsq_insert prefix in its name.


> > +             return scx_bpf_dsq_insert___new(p, dsq_id, slice, enq_flags);
> > +     } else {
> > +             scx_bpf_dsq_insert___compat(p, dsq_id, slice, enq_flags);
> > +             return true;
> >       }
> >  }
> >
> > --
> > 2.51.0
> >
>
> Thanks,
> -Andrea
>

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 3/4] sched_ext: Wrap kfunc args in struct to prepare for aux__prog
  2025-10-07  1:51 ` [PATCH 3/4] sched_ext: Wrap kfunc args in struct to prepare for aux__prog Tejun Heo
  2025-10-07  9:48   ` Andrea Righi
@ 2025-10-07 16:04   ` Emil Tsalapatis
  2025-10-07 16:38   ` Changwoo Min
  2 siblings, 0 replies; 26+ messages in thread
From: Emil Tsalapatis @ 2025-10-07 16:04 UTC (permalink / raw)
  To: Tejun Heo
  Cc: David Vernet, Andrea Righi, Changwoo Min, linux-kernel, sched-ext

On Mon, Oct 6, 2025 at 9:51 PM Tejun Heo <tj@kernel.org> wrote:
>
> scx_bpf_dsq_insert_vtime() and scx_bpf_select_cpu_and() currently have 5
> parameters. An upcoming change will add aux__prog parameter which will exceed
> BPF's 5 argument limit.
>
> Prepare by adding new kfuncs __scx_bpf_dsq_insert_vtime() and
> __scx_bpf_select_cpu_and() that take args structs. The existing kfuncs are
> kept as compatibility wrappers. BPF programs use inline wrappers that detect
> kernel API version via bpf_core_type_exists() and use the new struct-based
> kfuncs when available, falling back to compat kfuncs otherwise. This allows
> BPF programs to work with both old and new kernels.
>
> Signed-off-by: Tejun Heo <tj@kernel.org>

Reviewed-by: Emil Tsalapatis <emil@etsalapatis.com>

> ---
>  kernel/sched/ext.c                       | 82 ++++++++++++++++++------
>  kernel/sched/ext_idle.c                  | 43 +++++++++++--
>  tools/sched_ext/include/scx/common.bpf.h |  6 +-
>  tools/sched_ext/include/scx/compat.bpf.h | 72 +++++++++++++++++++++
>  4 files changed, 173 insertions(+), 30 deletions(-)
>
> diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c
> index 6d76efaaa9b2..a34e731229de 100644
> --- a/kernel/sched/ext.c
> +++ b/kernel/sched/ext.c
> @@ -5345,54 +5345,94 @@ __bpf_kfunc void scx_bpf_dsq_insert(struct task_struct *p, u64 dsq_id, u64 slice
>         scx_dsq_insert_commit(sch, p, dsq_id, enq_flags);
>  }
>
> +static void scx_dsq_insert_vtime(struct scx_sched *sch, struct task_struct *p,
> +                                u64 dsq_id, u64 slice, u64 vtime, u64 enq_flags)
> +{
> +       if (!scx_dsq_insert_preamble(sch, p, enq_flags))
> +               return;
> +
> +       if (slice)
> +               p->scx.slice = slice;
> +       else
> +               p->scx.slice = p->scx.slice ?: 1;
> +

Though the ?:1 logic is already in the code: I assume the rationale is
that we want the slice to be immediately exhausted so that the BPF
scheduler refills it with the right value, which makes sense.

> +       p->scx.dsq_vtime = vtime;
> +
> +       scx_dsq_insert_commit(sch, p, dsq_id, enq_flags | SCX_ENQ_DSQ_PRIQ);
> +}
> +
> +struct scx_bpf_dsq_insert_vtime_args {
> +       /* @p can't be packed together as KF_RCU is not transitive */
> +       u64                     dsq_id;
> +       u64                     slice;
> +       u64                     vtime;
> +       u64                     enq_flags;
> +};
> +
>  /**
> - * scx_bpf_dsq_insert_vtime - Insert a task into the vtime priority queue of a DSQ
> + * __scx_bpf_dsq_insert_vtime - Arg-wrapped vtime DSQ insertion
>   * @p: task_struct to insert
> - * @dsq_id: DSQ to insert into
> - * @slice: duration @p can run for in nsecs, 0 to keep the current value
> - * @vtime: @p's ordering inside the vtime-sorted queue of the target DSQ
> - * @enq_flags: SCX_ENQ_*
> + * @args: struct containing the rest of the arguments
> + *       @args->dsq_id: DSQ to insert into
> + *       @args->slice: duration @p can run for in nsecs, 0 to keep the current value
> + *       @args->vtime: @p's ordering inside the vtime-sorted queue of the target DSQ
> + *       @args->enq_flags: SCX_ENQ_*
>   *
> - * Insert @p into the vtime priority queue of the DSQ identified by @dsq_id.
> - * Tasks queued into the priority queue are ordered by @vtime. All other aspects
> - * are identical to scx_bpf_dsq_insert().
> + * Wrapper kfunc that takes arguments via struct to work around BPF's 5 argument
> + * limit. BPF programs should use scx_bpf_dsq_insert_vtime() which is provided
> + * as an inline wrapper in common.bpf.h.
>   *
> - * @vtime ordering is according to time_before64() which considers wrapping. A
> - * numerically larger vtime may indicate an earlier position in the ordering and
> - * vice-versa.
> + * Insert @p into the vtime priority queue of the DSQ identified by
> + * @args->dsq_id. Tasks queued into the priority queue are ordered by
> + * @args->vtime. All other aspects are identical to scx_bpf_dsq_insert().
> + *
> + * @args->vtime ordering is according to time_before64() which considers
> + * wrapping. A numerically larger vtime may indicate an earlier position in the
> + * ordering and vice-versa.
>   *
>   * A DSQ can only be used as a FIFO or priority queue at any given time and this
>   * function must not be called on a DSQ which already has one or more FIFO tasks
>   * queued and vice-versa. Also, the built-in DSQs (SCX_DSQ_LOCAL and
>   * SCX_DSQ_GLOBAL) cannot be used as priority queues.
>   */
> -__bpf_kfunc void scx_bpf_dsq_insert_vtime(struct task_struct *p, u64 dsq_id,
> -                                         u64 slice, u64 vtime, u64 enq_flags)
> +__bpf_kfunc void
> +__scx_bpf_dsq_insert_vtime(struct task_struct *p,
> +                          struct scx_bpf_dsq_insert_vtime_args *args)
>  {
>         struct scx_sched *sch;
>
>         guard(rcu)();
> +
>         sch = rcu_dereference(scx_root);
>         if (unlikely(!sch))
>                 return;
>
> -       if (!scx_dsq_insert_preamble(sch, p, enq_flags))
> -               return;
> +       scx_dsq_insert_vtime(sch, p, args->dsq_id, args->slice, args->vtime,
> +                            args->enq_flags);
> +}
>
> -       if (slice)
> -               p->scx.slice = slice;
> -       else
> -               p->scx.slice = p->scx.slice ?: 1;
> +/*
> + * COMPAT: Will be removed in v6.23.
> + */
> +__bpf_kfunc void scx_bpf_dsq_insert_vtime(struct task_struct *p, u64 dsq_id,
> +                                         u64 slice, u64 vtime, u64 enq_flags)
> +{
> +       struct scx_sched *sch;
>
> -       p->scx.dsq_vtime = vtime;
> +       guard(rcu)();
>
> -       scx_dsq_insert_commit(sch, p, dsq_id, enq_flags | SCX_ENQ_DSQ_PRIQ);
> +       sch = rcu_dereference(scx_root);
> +       if (unlikely(!sch))
> +               return;
> +
> +       scx_dsq_insert_vtime(sch, p, dsq_id, slice, vtime, enq_flags);
>  }
>
>  __bpf_kfunc_end_defs();
>
>  BTF_KFUNCS_START(scx_kfunc_ids_enqueue_dispatch)
>  BTF_ID_FLAGS(func, scx_bpf_dsq_insert, KF_RCU)
> +BTF_ID_FLAGS(func, __scx_bpf_dsq_insert_vtime, KF_RCU)
>  BTF_ID_FLAGS(func, scx_bpf_dsq_insert_vtime, KF_RCU)
>  BTF_KFUNCS_END(scx_kfunc_ids_enqueue_dispatch)
>
> diff --git a/kernel/sched/ext_idle.c b/kernel/sched/ext_idle.c
> index d2434c954848..3d9d404d5cd2 100644
> --- a/kernel/sched/ext_idle.c
> +++ b/kernel/sched/ext_idle.c
> @@ -995,26 +995,56 @@ __bpf_kfunc s32 scx_bpf_select_cpu_dfl(struct task_struct *p, s32 prev_cpu,
>         return prev_cpu;
>  }
>
> +struct scx_bpf_select_cpu_and_args {
> +       /* @p and @cpus_allowed can't be packed together as KF_RCU is not transitive */
> +       s32                     prev_cpu;
> +       u64                     wake_flags;
> +       u64                     flags;
> +};
> +
>  /**
> - * scx_bpf_select_cpu_and - Pick an idle CPU usable by task @p,
> - *                         prioritizing those in @cpus_allowed
> + * __scx_bpf_select_cpu_and - Arg-wrapped CPU selection with cpumask
>   * @p: task_struct to select a CPU for
> - * @prev_cpu: CPU @p was on previously
> - * @wake_flags: %SCX_WAKE_* flags
>   * @cpus_allowed: cpumask of allowed CPUs
> - * @flags: %SCX_PICK_IDLE* flags
> + * @args: struct containing the rest of the arguments
> + *       @args->prev_cpu: CPU @p was on previously
> + *       @args->wake_flags: %SCX_WAKE_* flags
> + *       @args->flags: %SCX_PICK_IDLE* flags
> + *
> + * Wrapper kfunc that takes arguments via struct to work around BPF's 5 argument
> + * limit. BPF programs should use scx_bpf_select_cpu_and() which is provided
> + * as an inline wrapper in common.bpf.h.
>   *
>   * Can be called from ops.select_cpu(), ops.enqueue(), or from an unlocked
>   * context such as a BPF test_run() call, as long as built-in CPU selection
>   * is enabled: ops.update_idle() is missing or %SCX_OPS_KEEP_BUILTIN_IDLE
>   * is set.
>   *
> - * @p, @prev_cpu and @wake_flags match ops.select_cpu().
> + * @p, @args->prev_cpu and @args->wake_flags match ops.select_cpu().
>   *
>   * Returns the selected idle CPU, which will be automatically awakened upon
>   * returning from ops.select_cpu() and can be used for direct dispatch, or
>   * a negative value if no idle CPU is available.
>   */
> +__bpf_kfunc s32
> +__scx_bpf_select_cpu_and(struct task_struct *p, const struct cpumask *cpus_allowed,
> +                        struct scx_bpf_select_cpu_and_args *args)
> +{
> +       struct scx_sched *sch;
> +
> +       guard(rcu)();
> +
> +       sch = rcu_dereference(scx_root);
> +       if (unlikely(!sch))
> +               return -ENODEV;
> +
> +       return select_cpu_from_kfunc(sch, p, args->prev_cpu, args->wake_flags,
> +                                    cpus_allowed, args->flags);
> +}
> +
> +/*
> + * COMPAT: Will be removed in v6.22.
> + */
>  __bpf_kfunc s32 scx_bpf_select_cpu_and(struct task_struct *p, s32 prev_cpu, u64 wake_flags,
>                                        const struct cpumask *cpus_allowed, u64 flags)
>  {
> @@ -1383,6 +1413,7 @@ BTF_ID_FLAGS(func, scx_bpf_pick_idle_cpu_node, KF_RCU)
>  BTF_ID_FLAGS(func, scx_bpf_pick_idle_cpu, KF_RCU)
>  BTF_ID_FLAGS(func, scx_bpf_pick_any_cpu_node, KF_RCU)
>  BTF_ID_FLAGS(func, scx_bpf_pick_any_cpu, KF_RCU)
> +BTF_ID_FLAGS(func, __scx_bpf_select_cpu_and, KF_RCU)
>  BTF_ID_FLAGS(func, scx_bpf_select_cpu_and, KF_RCU)
>  BTF_ID_FLAGS(func, scx_bpf_select_cpu_dfl, KF_RCU)
>  BTF_KFUNCS_END(scx_kfunc_ids_idle)
> diff --git a/tools/sched_ext/include/scx/common.bpf.h b/tools/sched_ext/include/scx/common.bpf.h
> index 505231b7b7ae..b1c2a0dde76e 100644
> --- a/tools/sched_ext/include/scx/common.bpf.h
> +++ b/tools/sched_ext/include/scx/common.bpf.h
> @@ -60,10 +60,10 @@ static inline void ___vmlinux_h_sanity_check___(void)
>
>  s32 scx_bpf_create_dsq(u64 dsq_id, s32 node) __ksym;
>  s32 scx_bpf_select_cpu_dfl(struct task_struct *p, s32 prev_cpu, u64 wake_flags, bool *is_idle) __ksym;
> -s32 scx_bpf_select_cpu_and(struct task_struct *p, s32 prev_cpu, u64 wake_flags,
> -                          const struct cpumask *cpus_allowed, u64 flags) __ksym __weak;
> +s32 __scx_bpf_select_cpu_and(struct task_struct *p, const struct cpumask *cpus_allowed,
> +                            struct scx_bpf_select_cpu_and_args *args) __ksym __weak;
>  void scx_bpf_dsq_insert(struct task_struct *p, u64 dsq_id, u64 slice, u64 enq_flags) __ksym __weak;
> -void scx_bpf_dsq_insert_vtime(struct task_struct *p, u64 dsq_id, u64 slice, u64 vtime, u64 enq_flags) __ksym __weak;
> +void __scx_bpf_dsq_insert_vtime(struct task_struct *p, struct scx_bpf_dsq_insert_vtime_args *args) __ksym __weak;
>  u32 scx_bpf_dispatch_nr_slots(void) __ksym;
>  void scx_bpf_dispatch_cancel(void) __ksym;
>  bool scx_bpf_dsq_move_to_local(u64 dsq_id) __ksym __weak;
> diff --git a/tools/sched_ext/include/scx/compat.bpf.h b/tools/sched_ext/include/scx/compat.bpf.h
> index d979f16a3ae2..e172de696f99 100644
> --- a/tools/sched_ext/include/scx/compat.bpf.h
> +++ b/tools/sched_ext/include/scx/compat.bpf.h
> @@ -143,6 +143,78 @@ static inline struct task_struct *__COMPAT_scx_bpf_cpu_curr(int cpu)
>         return rq ? rq->curr : NULL;
>  }
>
> +/*
> + * v6.19: To work around BPF maximum parameter limit, the following kfuncs are
> + * replaced with variants that pack scalar arguments in a struct. Wrappers are
> + * provided to maintain source compatibility.
> + *
> + * The kernel will carry the compat variants until v6.23 to maintain binary
> + * compatibility. After v6.23 release, remove the compat handling and move the
> + * wrappers to common.bpf.h.
> + */
> +s32 scx_bpf_select_cpu_and___compat(struct task_struct *p, s32 prev_cpu, u64 wake_flags,
> +                                   const struct cpumask *cpus_allowed, u64 flags) __ksym __weak;
> +void scx_bpf_dsq_insert_vtime___compat(struct task_struct *p, u64 dsq_id, u64 slice, u64 vtime, u64 enq_flags) __ksym __weak;
> +
> +/**
> + * scx_bpf_select_cpu_and - Pick an idle CPU usable by task @p
> + * @p: task_struct to select a CPU for
> + * @prev_cpu: CPU @p was on previously
> + * @wake_flags: %SCX_WAKE_* flags
> + * @cpus_allowed: cpumask of allowed CPUs
> + * @flags: %SCX_PICK_IDLE* flags
> + *
> + * Inline wrapper that packs scalar arguments into a struct and calls
> + * __scx_bpf_select_cpu_and(). See __scx_bpf_select_cpu_and() for details.
> + */
> +static inline s32
> +scx_bpf_select_cpu_and(struct task_struct *p, s32 prev_cpu, u64 wake_flags,
> +                      const struct cpumask *cpus_allowed, u64 flags)
> +{
> +       if (bpf_core_type_exists(struct scx_bpf_select_cpu_and_args)) {
> +               struct scx_bpf_select_cpu_and_args args = {
> +                       .prev_cpu = prev_cpu,
> +                       .wake_flags = wake_flags,
> +                       .flags = flags,
> +               };
> +
> +               return __scx_bpf_select_cpu_and(p, cpus_allowed, &args);
> +       } else {
> +               return scx_bpf_select_cpu_and___compat(p, prev_cpu, wake_flags,
> +                                                      cpus_allowed, flags);
> +       }
> +}
> +
> +/**
> + * scx_bpf_dsq_insert_vtime - Insert a task into the vtime priority queue of a DSQ
> + * @p: task_struct to insert
> + * @dsq_id: DSQ to insert into
> + * @slice: duration @p can run for in nsecs, 0 to keep the current value
> + * @vtime: @p's ordering inside the vtime-sorted queue of the target DSQ
> + * @enq_flags: SCX_ENQ_*
> + *
> + * Inline wrapper that packs scalar arguments into a struct and calls
> + * __scx_bpf_dsq_insert_vtime(). See __scx_bpf_dsq_insert_vtime() for details.
> + */
> +static inline void
> +scx_bpf_dsq_insert_vtime(struct task_struct *p, u64 dsq_id, u64 slice, u64 vtime,
> +                        u64 enq_flags)
> +{
> +       if (bpf_core_type_exists(struct scx_bpf_dsq_insert_vtime_args)) {
> +               struct scx_bpf_dsq_insert_vtime_args args = {
> +                       .dsq_id = dsq_id,
> +                       .slice = slice,
> +                       .vtime = vtime,
> +                       .enq_flags = enq_flags,
> +               };
> +
> +               __scx_bpf_dsq_insert_vtime(p, &args);
> +       } else {
> +               scx_bpf_dsq_insert_vtime___compat(p, dsq_id, slice, vtime,
> +                                                 enq_flags);
> +       }
> +}
> +
>  /*
>   * Define sched_ext_ops. This may be expanded to define multiple variants for
>   * backward compatibility. See compat.h::SCX_OPS_LOAD/ATTACH().
> --
> 2.51.0
>
>

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 1/4] tools/sched_ext: Strip compatibility macros for cgroup and dispatch APIs
  2025-10-07  1:51 ` [PATCH 1/4] tools/sched_ext: Strip compatibility macros for cgroup and dispatch APIs Tejun Heo
  2025-10-07  2:42   ` Emil Tsalapatis
  2025-10-07  9:42   ` Andrea Righi
@ 2025-10-07 16:22   ` Changwoo Min
  2 siblings, 0 replies; 26+ messages in thread
From: Changwoo Min @ 2025-10-07 16:22 UTC (permalink / raw)
  To: Tejun Heo, David Vernet, Andrea Righi; +Cc: linux-kernel, sched-ext



On 10/7/25 10:51, Tejun Heo wrote:
> Enough time has passed since the introduction of scx_bpf_task_cgroup() and
> the scx_bpf_dispatch* -> scx_bpf_dsq* kfunc renaming. Strip the compatibility
> macros.
> 
> Signed-off-by: Tejun Heo <tj@kernel.org>

Acked-by: Changwoo Min <changwoo@igalia.com>

Thanks!
Changwoo Min

> ---
>   tools/sched_ext/include/scx/compat.bpf.h | 108 +----------------------
>   tools/sched_ext/scx_flatcg.bpf.c         |  10 +--
>   tools/sched_ext/scx_qmap.bpf.c           |  14 ++-
>   3 files changed, 12 insertions(+), 120 deletions(-)
> 
> diff --git a/tools/sched_ext/include/scx/compat.bpf.h b/tools/sched_ext/include/scx/compat.bpf.h
> index dd9144624dc9..d979f16a3ae2 100644
> --- a/tools/sched_ext/include/scx/compat.bpf.h
> +++ b/tools/sched_ext/include/scx/compat.bpf.h
> @@ -15,121 +15,17 @@
>   	__ret;									\
>   })
>   
> -/* v6.12: 819513666966 ("sched_ext: Add cgroup support") */
> -#define __COMPAT_scx_bpf_task_cgroup(p)						\
> -	(bpf_ksym_exists(scx_bpf_task_cgroup) ?					\
> -	 scx_bpf_task_cgroup((p)) : NULL)
> -
>   /*
> - * v6.13: The verb `dispatch` was too overloaded and confusing. kfuncs are
> - * renamed to unload the verb.
> - *
> - * Build error is triggered if old names are used. New binaries work with both
> - * new and old names. The compat macros will be removed on v6.15 release.
> + * v6.15: 950ad93df2fc ("bpf: add kfunc for populating cpumask bits")
>    *
> - * scx_bpf_dispatch_from_dsq() and friends were added during v6.12 by
> - * 4c30f5ce4f7a ("sched_ext: Implement scx_bpf_dispatch[_vtime]_from_dsq()").
> - * Preserve __COMPAT macros until v6.15.
> + * Compat macro will be dropped on v6.19 release.
>    */
> -void scx_bpf_dispatch___compat(struct task_struct *p, u64 dsq_id, u64 slice, u64 enq_flags) __ksym __weak;
> -void scx_bpf_dispatch_vtime___compat(struct task_struct *p, u64 dsq_id, u64 slice, u64 vtime, u64 enq_flags) __ksym __weak;
> -bool scx_bpf_consume___compat(u64 dsq_id) __ksym __weak;
> -void scx_bpf_dispatch_from_dsq_set_slice___compat(struct bpf_iter_scx_dsq *it__iter, u64 slice) __ksym __weak;
> -void scx_bpf_dispatch_from_dsq_set_vtime___compat(struct bpf_iter_scx_dsq *it__iter, u64 vtime) __ksym __weak;
> -bool scx_bpf_dispatch_from_dsq___compat(struct bpf_iter_scx_dsq *it__iter, struct task_struct *p, u64 dsq_id, u64 enq_flags) __ksym __weak;
> -bool scx_bpf_dispatch_vtime_from_dsq___compat(struct bpf_iter_scx_dsq *it__iter, struct task_struct *p, u64 dsq_id, u64 enq_flags) __ksym __weak;
>   int bpf_cpumask_populate(struct cpumask *dst, void *src, size_t src__sz) __ksym __weak;
>   
> -#define scx_bpf_dsq_insert(p, dsq_id, slice, enq_flags)				\
> -	(bpf_ksym_exists(scx_bpf_dsq_insert) ?					\
> -	 scx_bpf_dsq_insert((p), (dsq_id), (slice), (enq_flags)) :		\
> -	 scx_bpf_dispatch___compat((p), (dsq_id), (slice), (enq_flags)))
> -
> -#define scx_bpf_dsq_insert_vtime(p, dsq_id, slice, vtime, enq_flags)		\
> -	(bpf_ksym_exists(scx_bpf_dsq_insert_vtime) ?				\
> -	 scx_bpf_dsq_insert_vtime((p), (dsq_id), (slice), (vtime), (enq_flags)) : \
> -	 scx_bpf_dispatch_vtime___compat((p), (dsq_id), (slice), (vtime), (enq_flags)))
> -
> -#define scx_bpf_dsq_move_to_local(dsq_id)					\
> -	(bpf_ksym_exists(scx_bpf_dsq_move_to_local) ?				\
> -	 scx_bpf_dsq_move_to_local((dsq_id)) :					\
> -	 scx_bpf_consume___compat((dsq_id)))
> -
> -#define __COMPAT_scx_bpf_dsq_move_set_slice(it__iter, slice)			\
> -	(bpf_ksym_exists(scx_bpf_dsq_move_set_slice) ?				\
> -	 scx_bpf_dsq_move_set_slice((it__iter), (slice)) :			\
> -	 (bpf_ksym_exists(scx_bpf_dispatch_from_dsq_set_slice___compat) ?	\
> -	  scx_bpf_dispatch_from_dsq_set_slice___compat((it__iter), (slice)) :	\
> -	  (void)0))
> -
> -#define __COMPAT_scx_bpf_dsq_move_set_vtime(it__iter, vtime)			\
> -	(bpf_ksym_exists(scx_bpf_dsq_move_set_vtime) ?				\
> -	 scx_bpf_dsq_move_set_vtime((it__iter), (vtime)) :			\
> -	 (bpf_ksym_exists(scx_bpf_dispatch_from_dsq_set_vtime___compat) ?	\
> -	  scx_bpf_dispatch_from_dsq_set_vtime___compat((it__iter), (vtime)) :	\
> -	  (void) 0))
> -
> -#define __COMPAT_scx_bpf_dsq_move(it__iter, p, dsq_id, enq_flags)		\
> -	(bpf_ksym_exists(scx_bpf_dsq_move) ?					\
> -	 scx_bpf_dsq_move((it__iter), (p), (dsq_id), (enq_flags)) :		\
> -	 (bpf_ksym_exists(scx_bpf_dispatch_from_dsq___compat) ?			\
> -	  scx_bpf_dispatch_from_dsq___compat((it__iter), (p), (dsq_id), (enq_flags)) : \
> -	  false))
> -
> -#define __COMPAT_scx_bpf_dsq_move_vtime(it__iter, p, dsq_id, enq_flags)		\
> -	(bpf_ksym_exists(scx_bpf_dsq_move_vtime) ?				\
> -	 scx_bpf_dsq_move_vtime((it__iter), (p), (dsq_id), (enq_flags)) :	\
> -	 (bpf_ksym_exists(scx_bpf_dispatch_vtime_from_dsq___compat) ?		\
> -	  scx_bpf_dispatch_vtime_from_dsq___compat((it__iter), (p), (dsq_id), (enq_flags)) : \
> -	  false))
> -
>   #define __COMPAT_bpf_cpumask_populate(cpumask, src, size__sz)		\
>   	(bpf_ksym_exists(bpf_cpumask_populate) ?			\
>   	 (bpf_cpumask_populate(cpumask, src, size__sz)) : -EOPNOTSUPP)
>   
> -#define scx_bpf_dispatch(p, dsq_id, slice, enq_flags)				\
> -	_Static_assert(false, "scx_bpf_dispatch() renamed to scx_bpf_dsq_insert()")
> -
> -#define scx_bpf_dispatch_vtime(p, dsq_id, slice, vtime, enq_flags)		\
> -	_Static_assert(false, "scx_bpf_dispatch_vtime() renamed to scx_bpf_dsq_insert_vtime()")
> -
> -#define scx_bpf_consume(dsq_id) ({						\
> -	_Static_assert(false, "scx_bpf_consume() renamed to scx_bpf_dsq_move_to_local()"); \
> -	false;									\
> -})
> -
> -#define scx_bpf_dispatch_from_dsq_set_slice(it__iter, slice)		\
> -	_Static_assert(false, "scx_bpf_dispatch_from_dsq_set_slice() renamed to scx_bpf_dsq_move_set_slice()")
> -
> -#define scx_bpf_dispatch_from_dsq_set_vtime(it__iter, vtime)		\
> -	_Static_assert(false, "scx_bpf_dispatch_from_dsq_set_vtime() renamed to scx_bpf_dsq_move_set_vtime()")
> -
> -#define scx_bpf_dispatch_from_dsq(it__iter, p, dsq_id, enq_flags) ({	\
> -	_Static_assert(false, "scx_bpf_dispatch_from_dsq() renamed to scx_bpf_dsq_move()"); \
> -	false;									\
> -})
> -
> -#define scx_bpf_dispatch_vtime_from_dsq(it__iter, p, dsq_id, enq_flags) ({  \
> -	_Static_assert(false, "scx_bpf_dispatch_vtime_from_dsq() renamed to scx_bpf_dsq_move_vtime()"); \
> -	false;									\
> -})
> -
> -#define __COMPAT_scx_bpf_dispatch_from_dsq_set_slice(it__iter, slice)		\
> -	_Static_assert(false, "__COMPAT_scx_bpf_dispatch_from_dsq_set_slice() renamed to __COMPAT_scx_bpf_dsq_move_set_slice()")
> -
> -#define __COMPAT_scx_bpf_dispatch_from_dsq_set_vtime(it__iter, vtime)		\
> -	_Static_assert(false, "__COMPAT_scx_bpf_dispatch_from_dsq_set_vtime() renamed to __COMPAT_scx_bpf_dsq_move_set_vtime()")
> -
> -#define __COMPAT_scx_bpf_dispatch_from_dsq(it__iter, p, dsq_id, enq_flags) ({	\
> -	_Static_assert(false, "__COMPAT_scx_bpf_dispatch_from_dsq() renamed to __COMPAT_scx_bpf_dsq_move()"); \
> -	false;									\
> -})
> -
> -#define __COMPAT_scx_bpf_dispatch_vtime_from_dsq(it__iter, p, dsq_id, enq_flags) ({  \
> -	_Static_assert(false, "__COMPAT_scx_bpf_dispatch_vtime_from_dsq() renamed to __COMPAT_scx_bpf_dsq_move_vtime()"); \
> -	false;									\
> -})
> -
>   /**
>    * __COMPAT_is_enq_cpu_selected - Test if SCX_ENQ_CPU_SELECTED is on
>    * in a compatible way. We will preserve this __COMPAT helper until v6.16.
> diff --git a/tools/sched_ext/scx_flatcg.bpf.c b/tools/sched_ext/scx_flatcg.bpf.c
> index 2c720e3ecad5..43126858b8e4 100644
> --- a/tools/sched_ext/scx_flatcg.bpf.c
> +++ b/tools/sched_ext/scx_flatcg.bpf.c
> @@ -382,7 +382,7 @@ void BPF_STRUCT_OPS(fcg_enqueue, struct task_struct *p, u64 enq_flags)
>   		return;
>   	}
>   
> -	cgrp = __COMPAT_scx_bpf_task_cgroup(p);
> +	cgrp = scx_bpf_task_cgroup(p);
>   	cgc = find_cgrp_ctx(cgrp);
>   	if (!cgc)
>   		goto out_release;
> @@ -508,7 +508,7 @@ void BPF_STRUCT_OPS(fcg_runnable, struct task_struct *p, u64 enq_flags)
>   {
>   	struct cgroup *cgrp;
>   
> -	cgrp = __COMPAT_scx_bpf_task_cgroup(p);
> +	cgrp = scx_bpf_task_cgroup(p);
>   	update_active_weight_sums(cgrp, true);
>   	bpf_cgroup_release(cgrp);
>   }
> @@ -521,7 +521,7 @@ void BPF_STRUCT_OPS(fcg_running, struct task_struct *p)
>   	if (fifo_sched)
>   		return;
>   
> -	cgrp = __COMPAT_scx_bpf_task_cgroup(p);
> +	cgrp = scx_bpf_task_cgroup(p);
>   	cgc = find_cgrp_ctx(cgrp);
>   	if (cgc) {
>   		/*
> @@ -564,7 +564,7 @@ void BPF_STRUCT_OPS(fcg_stopping, struct task_struct *p, bool runnable)
>   	if (!taskc->bypassed_at)
>   		return;
>   
> -	cgrp = __COMPAT_scx_bpf_task_cgroup(p);
> +	cgrp = scx_bpf_task_cgroup(p);
>   	cgc = find_cgrp_ctx(cgrp);
>   	if (cgc) {
>   		__sync_fetch_and_add(&cgc->cvtime_delta,
> @@ -578,7 +578,7 @@ void BPF_STRUCT_OPS(fcg_quiescent, struct task_struct *p, u64 deq_flags)
>   {
>   	struct cgroup *cgrp;
>   
> -	cgrp = __COMPAT_scx_bpf_task_cgroup(p);
> +	cgrp = scx_bpf_task_cgroup(p);
>   	update_active_weight_sums(cgrp, false);
>   	bpf_cgroup_release(cgrp);
>   }
> diff --git a/tools/sched_ext/scx_qmap.bpf.c b/tools/sched_ext/scx_qmap.bpf.c
> index 3072b593f898..c67dac78a4c6 100644
> --- a/tools/sched_ext/scx_qmap.bpf.c
> +++ b/tools/sched_ext/scx_qmap.bpf.c
> @@ -320,12 +320,9 @@ static bool dispatch_highpri(bool from_timer)
>   
>   		if (tctx->highpri) {
>   			/* exercise the set_*() and vtime interface too */
> -			__COMPAT_scx_bpf_dsq_move_set_slice(
> -				BPF_FOR_EACH_ITER, slice_ns * 2);
> -			__COMPAT_scx_bpf_dsq_move_set_vtime(
> -				BPF_FOR_EACH_ITER, highpri_seq++);
> -			__COMPAT_scx_bpf_dsq_move_vtime(
> -				BPF_FOR_EACH_ITER, p, HIGHPRI_DSQ, 0);
> +			scx_bpf_dsq_move_set_slice(BPF_FOR_EACH_ITER, slice_ns * 2);
> +			scx_bpf_dsq_move_set_vtime(BPF_FOR_EACH_ITER, highpri_seq++);
> +			scx_bpf_dsq_move_vtime(BPF_FOR_EACH_ITER, p, HIGHPRI_DSQ, 0);
>   		}
>   	}
>   
> @@ -342,9 +339,8 @@ static bool dispatch_highpri(bool from_timer)
>   		else
>   			cpu = scx_bpf_pick_any_cpu(p->cpus_ptr, 0);
>   
> -		if (__COMPAT_scx_bpf_dsq_move(BPF_FOR_EACH_ITER, p,
> -					      SCX_DSQ_LOCAL_ON | cpu,
> -					      SCX_ENQ_PREEMPT)) {
> +		if (scx_bpf_dsq_move(BPF_FOR_EACH_ITER, p, SCX_DSQ_LOCAL_ON | cpu,
> +				     SCX_ENQ_PREEMPT)) {
>   			if (cpu == this_cpu) {
>   				dispatched = true;
>   				__sync_fetch_and_add(&nr_expedited_local, 1);


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 2/4] sched_ext: Add scx_bpf_task_set_slice() and scx_bpf_task_set_dsq_vtime()
  2025-10-07  1:51 ` [PATCH 2/4] sched_ext: Add scx_bpf_task_set_slice() and scx_bpf_task_set_dsq_vtime() Tejun Heo
  2025-10-07  2:56   ` Emil Tsalapatis
  2025-10-07  9:34   ` Andrea Righi
@ 2025-10-07 16:28   ` Changwoo Min
  2025-10-07 18:11     ` Tejun Heo
  2 siblings, 1 reply; 26+ messages in thread
From: Changwoo Min @ 2025-10-07 16:28 UTC (permalink / raw)
  To: Tejun Heo, David Vernet, Andrea Righi; +Cc: linux-kernel, sched-ext


On 10/7/25 10:51, Tejun Heo wrote:
> With the planned hierarchical scheduler support, sub-schedulers will need to
> be verified for authority before being allowed to modify task->scx.slice and
> task->scx.dsq_vtime. Add scx_bpf_task_set_slice() and
> scx_bpf_task_set_dsq_vtime() which will perform the necessary permission
> checks.

Is it necessary to distinguish between decreasing the slice and
increasing the slice? A BPF scheduler (e.g., LAVD) sets the slice to
zero for passive preemption.

Regards,
Changwoo Min

> 
> Root schedulers can still directly write to these fields, so this doesn't
> affect existing schedulers.
> 
> Signed-off-by: Tejun Heo <tj@kernel.org>
> ---
>   kernel/sched/ext.c                       | 30 ++++++++++++++++++++++++
>   tools/sched_ext/include/scx/common.bpf.h |  2 ++
>   2 files changed, 32 insertions(+)
> 
> diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c
> index fc353b8d69f7..6d76efaaa9b2 100644
> --- a/kernel/sched/ext.c
> +++ b/kernel/sched/ext.c
> @@ -5833,6 +5833,34 @@ static const struct btf_kfunc_id_set scx_kfunc_set_unlocked = {
>   
>   __bpf_kfunc_start_defs();
>   
> +/**
> + * scx_bpf_task_set_slice - Set task's time slice
> + * @p: task of interest
> + * @slice: time slice to set in nsecs
> + *
> + * Set @p's time slice to @slice. Returns %true on success, %false if the
> + * calling scheduler doesn't have authority over @p.
> + */
> +__bpf_kfunc bool scx_bpf_task_set_slice(struct task_struct *p, u64 slice)
> +{
> +	p->scx.slice = slice;
> +	return true;
> +}
> +
> +/**
> + * scx_bpf_task_set_dsq_vtime - Set task's virtual time for DSQ ordering
> + * @p: task of interest
> + * @vtime: virtual time to set
> + *
> + * Set @p's virtual time to @vtime. Returns %true on success, %false if the
> + * calling scheduler doesn't have authority over @p.
> + */
> +__bpf_kfunc bool scx_bpf_task_set_dsq_vtime(struct task_struct *p, u64 vtime)
> +{
> +	p->scx.dsq_vtime = vtime;
> +	return true;
> +}
> +
>   static void scx_kick_cpu(struct scx_sched *sch, s32 cpu, u64 flags)
>   {
>   	struct rq *this_rq;
> @@ -6638,6 +6666,8 @@ __bpf_kfunc void scx_bpf_events(struct scx_event_stats *events,
>   __bpf_kfunc_end_defs();
>   
>   BTF_KFUNCS_START(scx_kfunc_ids_any)
> +BTF_ID_FLAGS(func, scx_bpf_task_set_slice, KF_RCU);
> +BTF_ID_FLAGS(func, scx_bpf_task_set_dsq_vtime, KF_RCU);
>   BTF_ID_FLAGS(func, scx_bpf_kick_cpu)
>   BTF_ID_FLAGS(func, scx_bpf_dsq_nr_queued)
>   BTF_ID_FLAGS(func, scx_bpf_destroy_dsq)
> diff --git a/tools/sched_ext/include/scx/common.bpf.h b/tools/sched_ext/include/scx/common.bpf.h
> index 06e2551033cb..505231b7b7ae 100644
> --- a/tools/sched_ext/include/scx/common.bpf.h
> +++ b/tools/sched_ext/include/scx/common.bpf.h
> @@ -102,6 +102,8 @@ s32 scx_bpf_pick_any_cpu_node(const cpumask_t *cpus_allowed, int node, u64 flags
>   s32 scx_bpf_pick_any_cpu(const cpumask_t *cpus_allowed, u64 flags) __ksym;
>   bool scx_bpf_task_running(const struct task_struct *p) __ksym;
>   s32 scx_bpf_task_cpu(const struct task_struct *p) __ksym;
> +bool scx_bpf_task_set_slice(struct task_struct *p, u64 slice) __ksym __weak;
> +bool scx_bpf_task_set_dsq_vtime(struct task_struct *p, u64 vtime) __ksym __weak;
>   struct rq *scx_bpf_cpu_rq(s32 cpu) __ksym;
>   struct rq *scx_bpf_locked_rq(void) __ksym;
>   struct task_struct *scx_bpf_cpu_curr(s32 cpu) __ksym __weak;


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 3/4] sched_ext: Wrap kfunc args in struct to prepare for aux__prog
  2025-10-07  1:51 ` [PATCH 3/4] sched_ext: Wrap kfunc args in struct to prepare for aux__prog Tejun Heo
  2025-10-07  9:48   ` Andrea Righi
  2025-10-07 16:04   ` Emil Tsalapatis
@ 2025-10-07 16:38   ` Changwoo Min
  2 siblings, 0 replies; 26+ messages in thread
From: Changwoo Min @ 2025-10-07 16:38 UTC (permalink / raw)
  To: Tejun Heo, David Vernet, Andrea Righi; +Cc: linux-kernel, sched-ext



On 10/7/25 10:51, Tejun Heo wrote:
> scx_bpf_dsq_insert_vtime() and scx_bpf_select_cpu_and() currently have 5
> parameters. An upcoming change will add aux__prog parameter which will exceed
> BPF's 5 argument limit.
> 
> Prepare by adding new kfuncs __scx_bpf_dsq_insert_vtime() and
> __scx_bpf_select_cpu_and() that take args structs. The existing kfuncs are
> kept as compatibility wrappers. BPF programs use inline wrappers that detect
> kernel API version via bpf_core_type_exists() and use the new struct-based
> kfuncs when available, falling back to compat kfuncs otherwise. This allows
> BPF programs to work with both old and new kernels.
> 
> Signed-off-by: Tejun Heo <tj@kernel.org>

Looks good to me.

Reviewed-by: Changwoo Min <changwoo@igalia.com>> ---
>   kernel/sched/ext.c                       | 82 ++++++++++++++++++------
>   kernel/sched/ext_idle.c                  | 43 +++++++++++--
>   tools/sched_ext/include/scx/common.bpf.h |  6 +-
>   tools/sched_ext/include/scx/compat.bpf.h | 72 +++++++++++++++++++++
>   4 files changed, 173 insertions(+), 30 deletions(-)
> 
> diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c
> index 6d76efaaa9b2..a34e731229de 100644
> --- a/kernel/sched/ext.c
> +++ b/kernel/sched/ext.c
> @@ -5345,54 +5345,94 @@ __bpf_kfunc void scx_bpf_dsq_insert(struct task_struct *p, u64 dsq_id, u64 slice
>   	scx_dsq_insert_commit(sch, p, dsq_id, enq_flags);
>   }
>   
> +static void scx_dsq_insert_vtime(struct scx_sched *sch, struct task_struct *p,
> +				 u64 dsq_id, u64 slice, u64 vtime, u64 enq_flags)
> +{
> +	if (!scx_dsq_insert_preamble(sch, p, enq_flags))
> +		return;
> +
> +	if (slice)
> +		p->scx.slice = slice;
> +	else
> +		p->scx.slice = p->scx.slice ?: 1;
> +
> +	p->scx.dsq_vtime = vtime;
> +
> +	scx_dsq_insert_commit(sch, p, dsq_id, enq_flags | SCX_ENQ_DSQ_PRIQ);
> +}
> +
> +struct scx_bpf_dsq_insert_vtime_args {
> +	/* @p can't be packed together as KF_RCU is not transitive */
> +	u64			dsq_id;
> +	u64			slice;
> +	u64			vtime;
> +	u64			enq_flags;
> +};
> +
>   /**
> - * scx_bpf_dsq_insert_vtime - Insert a task into the vtime priority queue of a DSQ
> + * __scx_bpf_dsq_insert_vtime - Arg-wrapped vtime DSQ insertion
>    * @p: task_struct to insert
> - * @dsq_id: DSQ to insert into
> - * @slice: duration @p can run for in nsecs, 0 to keep the current value
> - * @vtime: @p's ordering inside the vtime-sorted queue of the target DSQ
> - * @enq_flags: SCX_ENQ_*
> + * @args: struct containing the rest of the arguments
> + *       @args->dsq_id: DSQ to insert into
> + *       @args->slice: duration @p can run for in nsecs, 0 to keep the current value
> + *       @args->vtime: @p's ordering inside the vtime-sorted queue of the target DSQ
> + *       @args->enq_flags: SCX_ENQ_*
>    *
> - * Insert @p into the vtime priority queue of the DSQ identified by @dsq_id.
> - * Tasks queued into the priority queue are ordered by @vtime. All other aspects
> - * are identical to scx_bpf_dsq_insert().
> + * Wrapper kfunc that takes arguments via struct to work around BPF's 5 argument
> + * limit. BPF programs should use scx_bpf_dsq_insert_vtime() which is provided
> + * as an inline wrapper in common.bpf.h.
>    *
> - * @vtime ordering is according to time_before64() which considers wrapping. A
> - * numerically larger vtime may indicate an earlier position in the ordering and
> - * vice-versa.
> + * Insert @p into the vtime priority queue of the DSQ identified by
> + * @args->dsq_id. Tasks queued into the priority queue are ordered by
> + * @args->vtime. All other aspects are identical to scx_bpf_dsq_insert().
> + *
> + * @args->vtime ordering is according to time_before64() which considers
> + * wrapping. A numerically larger vtime may indicate an earlier position in the
> + * ordering and vice-versa.
>    *
>    * A DSQ can only be used as a FIFO or priority queue at any given time and this
>    * function must not be called on a DSQ which already has one or more FIFO tasks
>    * queued and vice-versa. Also, the built-in DSQs (SCX_DSQ_LOCAL and
>    * SCX_DSQ_GLOBAL) cannot be used as priority queues.
>    */
> -__bpf_kfunc void scx_bpf_dsq_insert_vtime(struct task_struct *p, u64 dsq_id,
> -					  u64 slice, u64 vtime, u64 enq_flags)
> +__bpf_kfunc void
> +__scx_bpf_dsq_insert_vtime(struct task_struct *p,
> +			   struct scx_bpf_dsq_insert_vtime_args *args)
>   {
>   	struct scx_sched *sch;
>   
>   	guard(rcu)();
> +
>   	sch = rcu_dereference(scx_root);
>   	if (unlikely(!sch))
>   		return;
>   
> -	if (!scx_dsq_insert_preamble(sch, p, enq_flags))
> -		return;
> +	scx_dsq_insert_vtime(sch, p, args->dsq_id, args->slice, args->vtime,
> +			     args->enq_flags);
> +}
>   
> -	if (slice)
> -		p->scx.slice = slice;
> -	else
> -		p->scx.slice = p->scx.slice ?: 1;
> +/*
> + * COMPAT: Will be removed in v6.23.
> + */
> +__bpf_kfunc void scx_bpf_dsq_insert_vtime(struct task_struct *p, u64 dsq_id,
> +					  u64 slice, u64 vtime, u64 enq_flags)
> +{
> +	struct scx_sched *sch;
>   
> -	p->scx.dsq_vtime = vtime;
> +	guard(rcu)();
>   
> -	scx_dsq_insert_commit(sch, p, dsq_id, enq_flags | SCX_ENQ_DSQ_PRIQ);
> +	sch = rcu_dereference(scx_root);
> +	if (unlikely(!sch))
> +		return;
> +
> +	scx_dsq_insert_vtime(sch, p, dsq_id, slice, vtime, enq_flags);
>   }
>   
>   __bpf_kfunc_end_defs();
>   
>   BTF_KFUNCS_START(scx_kfunc_ids_enqueue_dispatch)
>   BTF_ID_FLAGS(func, scx_bpf_dsq_insert, KF_RCU)
> +BTF_ID_FLAGS(func, __scx_bpf_dsq_insert_vtime, KF_RCU)
>   BTF_ID_FLAGS(func, scx_bpf_dsq_insert_vtime, KF_RCU)
>   BTF_KFUNCS_END(scx_kfunc_ids_enqueue_dispatch)
>   
> diff --git a/kernel/sched/ext_idle.c b/kernel/sched/ext_idle.c
> index d2434c954848..3d9d404d5cd2 100644
> --- a/kernel/sched/ext_idle.c
> +++ b/kernel/sched/ext_idle.c
> @@ -995,26 +995,56 @@ __bpf_kfunc s32 scx_bpf_select_cpu_dfl(struct task_struct *p, s32 prev_cpu,
>   	return prev_cpu;
>   }
>   
> +struct scx_bpf_select_cpu_and_args {
> +	/* @p and @cpus_allowed can't be packed together as KF_RCU is not transitive */
> +	s32			prev_cpu;
> +	u64			wake_flags;
> +	u64			flags;
> +};
> +
>   /**
> - * scx_bpf_select_cpu_and - Pick an idle CPU usable by task @p,
> - *			    prioritizing those in @cpus_allowed
> + * __scx_bpf_select_cpu_and - Arg-wrapped CPU selection with cpumask
>    * @p: task_struct to select a CPU for
> - * @prev_cpu: CPU @p was on previously
> - * @wake_flags: %SCX_WAKE_* flags
>    * @cpus_allowed: cpumask of allowed CPUs
> - * @flags: %SCX_PICK_IDLE* flags
> + * @args: struct containing the rest of the arguments
> + *       @args->prev_cpu: CPU @p was on previously
> + *       @args->wake_flags: %SCX_WAKE_* flags
> + *       @args->flags: %SCX_PICK_IDLE* flags
> + *
> + * Wrapper kfunc that takes arguments via struct to work around BPF's 5 argument
> + * limit. BPF programs should use scx_bpf_select_cpu_and() which is provided
> + * as an inline wrapper in common.bpf.h.
>    *
>    * Can be called from ops.select_cpu(), ops.enqueue(), or from an unlocked
>    * context such as a BPF test_run() call, as long as built-in CPU selection
>    * is enabled: ops.update_idle() is missing or %SCX_OPS_KEEP_BUILTIN_IDLE
>    * is set.
>    *
> - * @p, @prev_cpu and @wake_flags match ops.select_cpu().
> + * @p, @args->prev_cpu and @args->wake_flags match ops.select_cpu().
>    *
>    * Returns the selected idle CPU, which will be automatically awakened upon
>    * returning from ops.select_cpu() and can be used for direct dispatch, or
>    * a negative value if no idle CPU is available.
>    */
> +__bpf_kfunc s32
> +__scx_bpf_select_cpu_and(struct task_struct *p, const struct cpumask *cpus_allowed,
> +			 struct scx_bpf_select_cpu_and_args *args)
> +{
> +	struct scx_sched *sch;
> +
> +	guard(rcu)();
> +
> +	sch = rcu_dereference(scx_root);
> +	if (unlikely(!sch))
> +		return -ENODEV;
> +
> +	return select_cpu_from_kfunc(sch, p, args->prev_cpu, args->wake_flags,
> +				     cpus_allowed, args->flags);
> +}
> +
> +/*
> + * COMPAT: Will be removed in v6.22.
> + */
>   __bpf_kfunc s32 scx_bpf_select_cpu_and(struct task_struct *p, s32 prev_cpu, u64 wake_flags,
>   				       const struct cpumask *cpus_allowed, u64 flags)
>   {
> @@ -1383,6 +1413,7 @@ BTF_ID_FLAGS(func, scx_bpf_pick_idle_cpu_node, KF_RCU)
>   BTF_ID_FLAGS(func, scx_bpf_pick_idle_cpu, KF_RCU)
>   BTF_ID_FLAGS(func, scx_bpf_pick_any_cpu_node, KF_RCU)
>   BTF_ID_FLAGS(func, scx_bpf_pick_any_cpu, KF_RCU)
> +BTF_ID_FLAGS(func, __scx_bpf_select_cpu_and, KF_RCU)
>   BTF_ID_FLAGS(func, scx_bpf_select_cpu_and, KF_RCU)
>   BTF_ID_FLAGS(func, scx_bpf_select_cpu_dfl, KF_RCU)
>   BTF_KFUNCS_END(scx_kfunc_ids_idle)
> diff --git a/tools/sched_ext/include/scx/common.bpf.h b/tools/sched_ext/include/scx/common.bpf.h
> index 505231b7b7ae..b1c2a0dde76e 100644
> --- a/tools/sched_ext/include/scx/common.bpf.h
> +++ b/tools/sched_ext/include/scx/common.bpf.h
> @@ -60,10 +60,10 @@ static inline void ___vmlinux_h_sanity_check___(void)
>   
>   s32 scx_bpf_create_dsq(u64 dsq_id, s32 node) __ksym;
>   s32 scx_bpf_select_cpu_dfl(struct task_struct *p, s32 prev_cpu, u64 wake_flags, bool *is_idle) __ksym;
> -s32 scx_bpf_select_cpu_and(struct task_struct *p, s32 prev_cpu, u64 wake_flags,
> -			   const struct cpumask *cpus_allowed, u64 flags) __ksym __weak;
> +s32 __scx_bpf_select_cpu_and(struct task_struct *p, const struct cpumask *cpus_allowed,
> +			     struct scx_bpf_select_cpu_and_args *args) __ksym __weak;
>   void scx_bpf_dsq_insert(struct task_struct *p, u64 dsq_id, u64 slice, u64 enq_flags) __ksym __weak;
> -void scx_bpf_dsq_insert_vtime(struct task_struct *p, u64 dsq_id, u64 slice, u64 vtime, u64 enq_flags) __ksym __weak;
> +void __scx_bpf_dsq_insert_vtime(struct task_struct *p, struct scx_bpf_dsq_insert_vtime_args *args) __ksym __weak;
>   u32 scx_bpf_dispatch_nr_slots(void) __ksym;
>   void scx_bpf_dispatch_cancel(void) __ksym;
>   bool scx_bpf_dsq_move_to_local(u64 dsq_id) __ksym __weak;
> diff --git a/tools/sched_ext/include/scx/compat.bpf.h b/tools/sched_ext/include/scx/compat.bpf.h
> index d979f16a3ae2..e172de696f99 100644
> --- a/tools/sched_ext/include/scx/compat.bpf.h
> +++ b/tools/sched_ext/include/scx/compat.bpf.h
> @@ -143,6 +143,78 @@ static inline struct task_struct *__COMPAT_scx_bpf_cpu_curr(int cpu)
>   	return rq ? rq->curr : NULL;
>   }
>   
> +/*
> + * v6.19: To work around BPF maximum parameter limit, the following kfuncs are
> + * replaced with variants that pack scalar arguments in a struct. Wrappers are
> + * provided to maintain source compatibility.
> + *
> + * The kernel will carry the compat variants until v6.23 to maintain binary
> + * compatibility. After v6.23 release, remove the compat handling and move the
> + * wrappers to common.bpf.h.
> + */
> +s32 scx_bpf_select_cpu_and___compat(struct task_struct *p, s32 prev_cpu, u64 wake_flags,
> +				    const struct cpumask *cpus_allowed, u64 flags) __ksym __weak;
> +void scx_bpf_dsq_insert_vtime___compat(struct task_struct *p, u64 dsq_id, u64 slice, u64 vtime, u64 enq_flags) __ksym __weak;
> +
> +/**
> + * scx_bpf_select_cpu_and - Pick an idle CPU usable by task @p
> + * @p: task_struct to select a CPU for
> + * @prev_cpu: CPU @p was on previously
> + * @wake_flags: %SCX_WAKE_* flags
> + * @cpus_allowed: cpumask of allowed CPUs
> + * @flags: %SCX_PICK_IDLE* flags
> + *
> + * Inline wrapper that packs scalar arguments into a struct and calls
> + * __scx_bpf_select_cpu_and(). See __scx_bpf_select_cpu_and() for details.
> + */
> +static inline s32
> +scx_bpf_select_cpu_and(struct task_struct *p, s32 prev_cpu, u64 wake_flags,
> +		       const struct cpumask *cpus_allowed, u64 flags)
> +{
> +	if (bpf_core_type_exists(struct scx_bpf_select_cpu_and_args)) {
> +		struct scx_bpf_select_cpu_and_args args = {
> +			.prev_cpu = prev_cpu,
> +			.wake_flags = wake_flags,
> +			.flags = flags,
> +		};
> +
> +		return __scx_bpf_select_cpu_and(p, cpus_allowed, &args);
> +	} else {
> +		return scx_bpf_select_cpu_and___compat(p, prev_cpu, wake_flags,
> +						       cpus_allowed, flags);
> +	}
> +}
> +
> +/**
> + * scx_bpf_dsq_insert_vtime - Insert a task into the vtime priority queue of a DSQ
> + * @p: task_struct to insert
> + * @dsq_id: DSQ to insert into
> + * @slice: duration @p can run for in nsecs, 0 to keep the current value
> + * @vtime: @p's ordering inside the vtime-sorted queue of the target DSQ
> + * @enq_flags: SCX_ENQ_*
> + *
> + * Inline wrapper that packs scalar arguments into a struct and calls
> + * __scx_bpf_dsq_insert_vtime(). See __scx_bpf_dsq_insert_vtime() for details.
> + */
> +static inline void
> +scx_bpf_dsq_insert_vtime(struct task_struct *p, u64 dsq_id, u64 slice, u64 vtime,
> +			 u64 enq_flags)
> +{
> +	if (bpf_core_type_exists(struct scx_bpf_dsq_insert_vtime_args)) {
> +		struct scx_bpf_dsq_insert_vtime_args args = {
> +			.dsq_id = dsq_id,
> +			.slice = slice,
> +			.vtime = vtime,
> +			.enq_flags = enq_flags,
> +		};
> +
> +		__scx_bpf_dsq_insert_vtime(p, &args);
> +	} else {
> +		scx_bpf_dsq_insert_vtime___compat(p, dsq_id, slice, vtime,
> +						  enq_flags);
> +	}
> +}
> +
>   /*
>    * Define sched_ext_ops. This may be expanded to define multiple variants for
>    * backward compatibility. See compat.h::SCX_OPS_LOAD/ATTACH().


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 4/4] sched_ext: Make scx_bpf_dsq_insert*() return bool
  2025-10-07  1:51 ` [PATCH 4/4] sched_ext: Make scx_bpf_dsq_insert*() return bool Tejun Heo
  2025-10-07  4:28   ` Emil Tsalapatis
  2025-10-07  9:41   ` Andrea Righi
@ 2025-10-07 16:47   ` Changwoo Min
  2 siblings, 0 replies; 26+ messages in thread
From: Changwoo Min @ 2025-10-07 16:47 UTC (permalink / raw)
  To: Tejun Heo, David Vernet, Andrea Righi; +Cc: linux-kernel, sched-ext



On 10/7/25 10:51, Tejun Heo wrote:
> In preparation for hierarchical schedulers, change scx_bpf_dsq_insert() and
> scx_bpf_dsq_insert_vtime() to return bool instead of void. With
> sub-schedulers, there will be no reliable way to guarantee a task is still
> owned by the sub-scheduler at insertion time (e.g., the task may have been
> migrated to another scheduler). The bool return value will enable
> sub-schedulers to detect and gracefully handle insertion failures.
> 
> For the root scheduler, insertion failures will continue to trigger scheduler
> abort via scx_error(), so existing code doesn't need to check the return
> value. Backward compatibility is maintained through compat wrappers.
> 
> Also update scx_bpf_dsq_move() documentation to clarify that it can return
> false for sub-schedulers when @dsq_id points to a disallowed local DSQ.
> 
> Signed-off-by: Tejun Heo <tj@kernel.org>

Looks good to me.

Reviewed-by: Changwoo Min <changwoo@igalia.com>

Regards,
Changwoo Min


> ---
>   kernel/sched/ext.c                       | 45 ++++++++++++++++++------
>   tools/sched_ext/include/scx/common.bpf.h |  3 +-
>   tools/sched_ext/include/scx/compat.bpf.h | 23 ++++++++++--
>   3 files changed, 56 insertions(+), 15 deletions(-)
> 
> diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c
> index a34e731229de..399e53c8939c 100644
> --- a/kernel/sched/ext.c
> +++ b/kernel/sched/ext.c
> @@ -5323,8 +5323,12 @@ __bpf_kfunc_start_defs();
>    * exhaustion. If zero, the current residual slice is maintained. If
>    * %SCX_SLICE_INF, @p never expires and the BPF scheduler must kick the CPU with
>    * scx_bpf_kick_cpu() to trigger scheduling.
> + *
> + * Returns %true on successful insertion, %false on failure. On the root
> + * scheduler, %false return triggers scheduler abort and the caller doesn't need
> + * to check the return value.
>    */
> -__bpf_kfunc void scx_bpf_dsq_insert(struct task_struct *p, u64 dsq_id, u64 slice,
> +__bpf_kfunc bool scx_bpf_dsq_insert(struct task_struct *p, u64 dsq_id, u64 slice,
>   				    u64 enq_flags)
>   {
>   	struct scx_sched *sch;
> @@ -5332,10 +5336,10 @@ __bpf_kfunc void scx_bpf_dsq_insert(struct task_struct *p, u64 dsq_id, u64 slice
>   	guard(rcu)();
>   	sch = rcu_dereference(scx_root);
>   	if (unlikely(!sch))
> -		return;
> +		return false;
>   
>   	if (!scx_dsq_insert_preamble(sch, p, enq_flags))
> -		return;
> +		return false;
>   
>   	if (slice)
>   		p->scx.slice = slice;
> @@ -5343,13 +5347,24 @@ __bpf_kfunc void scx_bpf_dsq_insert(struct task_struct *p, u64 dsq_id, u64 slice
>   		p->scx.slice = p->scx.slice ?: 1;
>   
>   	scx_dsq_insert_commit(sch, p, dsq_id, enq_flags);
> +
> +	return true;
> +}
> +
> +/*
> + * COMPAT: Will be removed in v6.23.
> + */
> +__bpf_kfunc void scx_bpf_dsq_insert___compat(struct task_struct *p, u64 dsq_id,
> +					     u64 slice, u64 enq_flags)
> +{
> +	scx_bpf_dsq_insert(p, dsq_id, slice, enq_flags);
>   }
>   
> -static void scx_dsq_insert_vtime(struct scx_sched *sch, struct task_struct *p,
> +static bool scx_dsq_insert_vtime(struct scx_sched *sch, struct task_struct *p,
>   				 u64 dsq_id, u64 slice, u64 vtime, u64 enq_flags)
>   {
>   	if (!scx_dsq_insert_preamble(sch, p, enq_flags))
> -		return;
> +		return false;
>   
>   	if (slice)
>   		p->scx.slice = slice;
> @@ -5359,6 +5374,8 @@ static void scx_dsq_insert_vtime(struct scx_sched *sch, struct task_struct *p,
>   	p->scx.dsq_vtime = vtime;
>   
>   	scx_dsq_insert_commit(sch, p, dsq_id, enq_flags | SCX_ENQ_DSQ_PRIQ);
> +
> +	return true;
>   }
>   
>   struct scx_bpf_dsq_insert_vtime_args {
> @@ -5394,8 +5411,12 @@ struct scx_bpf_dsq_insert_vtime_args {
>    * function must not be called on a DSQ which already has one or more FIFO tasks
>    * queued and vice-versa. Also, the built-in DSQs (SCX_DSQ_LOCAL and
>    * SCX_DSQ_GLOBAL) cannot be used as priority queues.
> + *
> + * Returns %true on successful insertion, %false on failure. On the root
> + * scheduler, %false return triggers scheduler abort and the caller doesn't need
> + * to check the return value.
>    */
> -__bpf_kfunc void
> +__bpf_kfunc bool
>   __scx_bpf_dsq_insert_vtime(struct task_struct *p,
>   			   struct scx_bpf_dsq_insert_vtime_args *args)
>   {
> @@ -5405,10 +5426,10 @@ __scx_bpf_dsq_insert_vtime(struct task_struct *p,
>   
>   	sch = rcu_dereference(scx_root);
>   	if (unlikely(!sch))
> -		return;
> +		return false;
>   
> -	scx_dsq_insert_vtime(sch, p, args->dsq_id, args->slice, args->vtime,
> -			     args->enq_flags);
> +	return scx_dsq_insert_vtime(sch, p, args->dsq_id, args->slice,
> +				    args->vtime, args->enq_flags);
>   }
>   
>   /*
> @@ -5432,6 +5453,7 @@ __bpf_kfunc_end_defs();
>   
>   BTF_KFUNCS_START(scx_kfunc_ids_enqueue_dispatch)
>   BTF_ID_FLAGS(func, scx_bpf_dsq_insert, KF_RCU)
> +BTF_ID_FLAGS(func, scx_bpf_dsq_insert___compat, KF_RCU)
>   BTF_ID_FLAGS(func, __scx_bpf_dsq_insert_vtime, KF_RCU)
>   BTF_ID_FLAGS(func, scx_bpf_dsq_insert_vtime, KF_RCU)
>   BTF_KFUNCS_END(scx_kfunc_ids_enqueue_dispatch)
> @@ -5686,8 +5708,9 @@ __bpf_kfunc void scx_bpf_dsq_move_set_vtime(struct bpf_iter_scx_dsq *it__iter,
>    * Can be called from ops.dispatch() or any BPF context which doesn't hold a rq
>    * lock (e.g. BPF timers or SYSCALL programs).
>    *
> - * Returns %true if @p has been consumed, %false if @p had already been consumed
> - * or dequeued.
> + * Returns %true if @p has been consumed, %false if @p had already been
> + * consumed, dequeued, or, for sub-scheds, @dsq_id points to a disallowed local
> + * DSQ.
>    */
>   __bpf_kfunc bool scx_bpf_dsq_move(struct bpf_iter_scx_dsq *it__iter,
>   				  struct task_struct *p, u64 dsq_id,
> diff --git a/tools/sched_ext/include/scx/common.bpf.h b/tools/sched_ext/include/scx/common.bpf.h
> index b1c2a0dde76e..522c90d0ced2 100644
> --- a/tools/sched_ext/include/scx/common.bpf.h
> +++ b/tools/sched_ext/include/scx/common.bpf.h
> @@ -62,8 +62,7 @@ s32 scx_bpf_create_dsq(u64 dsq_id, s32 node) __ksym;
>   s32 scx_bpf_select_cpu_dfl(struct task_struct *p, s32 prev_cpu, u64 wake_flags, bool *is_idle) __ksym;
>   s32 __scx_bpf_select_cpu_and(struct task_struct *p, const struct cpumask *cpus_allowed,
>   			     struct scx_bpf_select_cpu_and_args *args) __ksym __weak;
> -void scx_bpf_dsq_insert(struct task_struct *p, u64 dsq_id, u64 slice, u64 enq_flags) __ksym __weak;
> -void __scx_bpf_dsq_insert_vtime(struct task_struct *p, struct scx_bpf_dsq_insert_vtime_args *args) __ksym __weak;
> +bool __scx_bpf_dsq_insert_vtime(struct task_struct *p, struct scx_bpf_dsq_insert_vtime_args *args) __ksym __weak;
>   u32 scx_bpf_dispatch_nr_slots(void) __ksym;
>   void scx_bpf_dispatch_cancel(void) __ksym;
>   bool scx_bpf_dsq_move_to_local(u64 dsq_id) __ksym __weak;
> diff --git a/tools/sched_ext/include/scx/compat.bpf.h b/tools/sched_ext/include/scx/compat.bpf.h
> index e172de696f99..33c26928f4e9 100644
> --- a/tools/sched_ext/include/scx/compat.bpf.h
> +++ b/tools/sched_ext/include/scx/compat.bpf.h
> @@ -196,7 +196,7 @@ scx_bpf_select_cpu_and(struct task_struct *p, s32 prev_cpu, u64 wake_flags,
>    * Inline wrapper that packs scalar arguments into a struct and calls
>    * __scx_bpf_dsq_insert_vtime(). See __scx_bpf_dsq_insert_vtime() for details.
>    */
> -static inline void
> +static inline bool
>   scx_bpf_dsq_insert_vtime(struct task_struct *p, u64 dsq_id, u64 slice, u64 vtime,
>   			 u64 enq_flags)
>   {
> @@ -208,10 +208,29 @@ scx_bpf_dsq_insert_vtime(struct task_struct *p, u64 dsq_id, u64 slice, u64 vtime
>   			.enq_flags = enq_flags,
>   		};
>   
> -		__scx_bpf_dsq_insert_vtime(p, &args);
> +		return __scx_bpf_dsq_insert_vtime(p, &args);
>   	} else {
>   		scx_bpf_dsq_insert_vtime___compat(p, dsq_id, slice, vtime,
>   						  enq_flags);
> +		return true;
> +	}
> +}
> +
> +/*
> + * v6.19: scx_bpf_dsq_insert() now returns bool instead of void. Move
> + * scx_bpf_dsq_insert() decl to common.bpf.h and drop compat helper after v6.22.
> + */
> +bool scx_bpf_dsq_insert___new(struct task_struct *p, u64 dsq_id, u64 slice, u64 enq_flags) __ksym __weak;
> +void scx_bpf_dsq_insert___compat(struct task_struct *p, u64 dsq_id, u64 slice, u64 enq_flags) __ksym __weak;
> +
> +static inline bool
> +scx_bpf_dsq_insert(struct task_struct *p, u64 dsq_id, u64 slice, u64 enq_flags)
> +{
> +	if (bpf_ksym_exists(scx_bpf_dsq_insert___new)) {
> +		return scx_bpf_dsq_insert___new(p, dsq_id, slice, enq_flags);
> +	} else {
> +		scx_bpf_dsq_insert___compat(p, dsq_id, slice, enq_flags);
> +		return true;
>   	}
>   }
>   


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 4/4] sched_ext: Make scx_bpf_dsq_insert*() return bool
  2025-10-07 15:03     ` Emil Tsalapatis
@ 2025-10-07 17:25       ` Andrea Righi
  0 siblings, 0 replies; 26+ messages in thread
From: Andrea Righi @ 2025-10-07 17:25 UTC (permalink / raw)
  To: Emil Tsalapatis
  Cc: Tejun Heo, David Vernet, Changwoo Min, linux-kernel, sched-ext

On Tue, Oct 07, 2025 at 11:03:04AM -0400, Emil Tsalapatis wrote:
...
> > > +/*
> > > + * v6.19: scx_bpf_dsq_insert() now returns bool instead of void. Move
> > > + * scx_bpf_dsq_insert() decl to common.bpf.h and drop compat helper after v6.22.
> > > + */
> > > +bool scx_bpf_dsq_insert___new(struct task_struct *p, u64 dsq_id, u64 slice, u64 enq_flags) __ksym __weak;
> > > +void scx_bpf_dsq_insert___compat(struct task_struct *p, u64 dsq_id, u64 slice, u64 enq_flags) __ksym __weak;
> > > +
> > > +static inline bool
> > > +scx_bpf_dsq_insert(struct task_struct *p, u64 dsq_id, u64 slice, u64 enq_flags)
> > > +{
> > > +     if (bpf_ksym_exists(scx_bpf_dsq_insert___new)) {
> >
> > I'm confused... where is scx_bpf_dsq_insert___new() defined?
> >
> 
> CO:RE relocation ignores suffixes if there is no match, so
> scx_bpf_dsq_insert___new() defaults to scx_bpf_dsq_insert() in systems
> with this patch. When I tested it the symbol resolved to
> scx_bpf_dsq_insert(). We're not really matching the name, we're
> matching the signature and trying to find a kfunc with the the
> scx_bpf_dsq_insert prefix in its name.

I see, TIL. Thanks for clarifing this, Emil. With that:

Acked-by: Andrea Righi <arighi@nvidia.com>

-Andrea

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 2/4] sched_ext: Add scx_bpf_task_set_slice() and scx_bpf_task_set_dsq_vtime()
  2025-10-07  2:56   ` Emil Tsalapatis
@ 2025-10-07 18:09     ` Tejun Heo
  0 siblings, 0 replies; 26+ messages in thread
From: Tejun Heo @ 2025-10-07 18:09 UTC (permalink / raw)
  To: Emil Tsalapatis
  Cc: David Vernet, Andrea Righi, Changwoo Min, linux-kernel, sched-ext

Hello,

On Mon, Oct 06, 2025 at 10:56:45PM -0400, Emil Tsalapatis wrote:
> > +/**
> > + * scx_bpf_task_set_slice - Set task's time slice
> > + * @p: task of interest
> > + * @slice: time slice to set in nsecs
> > + *
> > + * Set @p's time slice to @slice. Returns %true on success, %false if the
> > + * calling scheduler doesn't have authority over @p.
> > + */
> > +__bpf_kfunc bool scx_bpf_task_set_slice(struct task_struct *p, u64 slice)
> > +{
> > +       p->scx.slice = slice;
> > +       return true;
> > +}
> > +
> 
> Q: Do we care about protecting slice/dsq_vtime these fields with a
> lock (e.g., to let them be atomically changed w/ other
> proc/DSQ state? If so, should we limit them with the kf_mask to be
> callable from specific BPF ops?

I think it'd be the calling BPF scheduler's responsibility to synchronize if
there are multiple writers. I don't think such scenarios are likely tho.
Schedulers almost always have clearly defined chain of custody for each
task. Also, there's nothing to synchronize on 64bit machines. These are
isolated writes (ie. adding locking doesn't change the possible outcomes).

Thanks.

-- 
tejun

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 2/4] sched_ext: Add scx_bpf_task_set_slice() and scx_bpf_task_set_dsq_vtime()
  2025-10-07  9:34   ` Andrea Righi
@ 2025-10-07 18:09     ` Tejun Heo
  0 siblings, 0 replies; 26+ messages in thread
From: Tejun Heo @ 2025-10-07 18:09 UTC (permalink / raw)
  To: Andrea Righi; +Cc: David Vernet, Changwoo Min, linux-kernel, sched-ext

On Tue, Oct 07, 2025 at 11:34:56AM +0200, Andrea Righi wrote:
> Hi Tejun,
> 
> On Mon, Oct 06, 2025 at 03:51:45PM -1000, Tejun Heo wrote:
> > With the planned hierarchical scheduler support, sub-schedulers will need to
> > be verified for authority before being allowed to modify task->scx.slice and
> > task->scx.dsq_vtime. Add scx_bpf_task_set_slice() and
> > scx_bpf_task_set_dsq_vtime() which will perform the necessary permission
> > checks.
> > 
> > Root schedulers can still directly write to these fields, so this doesn't
> > affect existing schedulers.
> > 
> > Signed-off-by: Tejun Heo <tj@kernel.org>
> > ---
> 
> Maybe provide __COMPAT_scx_bpf_task_set_slice() and
> __COMPAT_scx_bpf_task_set_dsq_vtime(), but we can do this later.

Ah, right. Will do.

Thanks.

-- 
tejun

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 2/4] sched_ext: Add scx_bpf_task_set_slice() and scx_bpf_task_set_dsq_vtime()
  2025-10-07 16:28   ` Changwoo Min
@ 2025-10-07 18:11     ` Tejun Heo
  0 siblings, 0 replies; 26+ messages in thread
From: Tejun Heo @ 2025-10-07 18:11 UTC (permalink / raw)
  To: Changwoo Min; +Cc: David Vernet, Andrea Righi, linux-kernel, sched-ext

On Wed, Oct 08, 2025 at 01:28:31AM +0900, Changwoo Min wrote:
> 
> On 10/7/25 10:51, Tejun Heo wrote:
> > With the planned hierarchical scheduler support, sub-schedulers will need to
> > be verified for authority before being allowed to modify task->scx.slice and
> > task->scx.dsq_vtime. Add scx_bpf_task_set_slice() and
> > scx_bpf_task_set_dsq_vtime() which will perform the necessary permission
> > checks.
> 
> Is it necessary to distinguish between decreasing the slice and
> increasing the slice? A BPF scheduler (e.g., LAVD) sets the slice to
> zero for passive preemption.

It's going to be a simple "does this scheduler own this task?" test, I don't
think it needs to look at how the value is being changed.

Thanks.

-- 
tejun

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 3/4] sched_ext: Wrap kfunc args in struct to prepare for aux__prog
  2025-10-07  9:48   ` Andrea Righi
@ 2025-10-07 18:24     ` Tejun Heo
  2025-10-07 18:37       ` Andrea Righi
  0 siblings, 1 reply; 26+ messages in thread
From: Tejun Heo @ 2025-10-07 18:24 UTC (permalink / raw)
  To: Andrea Righi; +Cc: David Vernet, Changwoo Min, linux-kernel, sched-ext

Hello,

On Tue, Oct 07, 2025 at 11:48:44AM +0200, Andrea Righi wrote:
> > +struct scx_bpf_dsq_insert_vtime_args {
> > +	/* @p can't be packed together as KF_RCU is not transitive */
> > +	u64			dsq_id;
> > +	u64			slice;
> > +	u64			vtime;
> > +	u64			enq_flags;
> > +};
> 
> With PATCH 2/4 introducing scx_bpf_task_set_slice() and
> scx_bpf_task_set_dsq_vtime(), would it be reasonable to use those to set
> these task properties and then completely get rid of these args in
> scx_bpf_dsq_insert[_vtime]()?

Maybe. However, the most common usage pattern is setting vtime and slice on
insertion, so I think it makes sense to have a shortcut interface for that.
Even if the overhead difference is negligible, it's nice to have a dedicated
interface for the most common use case.

Thanks.

-- 
tejun

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 3/4] sched_ext: Wrap kfunc args in struct to prepare for aux__prog
  2025-10-07 18:24     ` Tejun Heo
@ 2025-10-07 18:37       ` Andrea Righi
  0 siblings, 0 replies; 26+ messages in thread
From: Andrea Righi @ 2025-10-07 18:37 UTC (permalink / raw)
  To: Tejun Heo; +Cc: David Vernet, Changwoo Min, linux-kernel, sched-ext

On Tue, Oct 07, 2025 at 08:24:02AM -1000, Tejun Heo wrote:
> Hello,
> 
> On Tue, Oct 07, 2025 at 11:48:44AM +0200, Andrea Righi wrote:
> > > +struct scx_bpf_dsq_insert_vtime_args {
> > > +	/* @p can't be packed together as KF_RCU is not transitive */
> > > +	u64			dsq_id;
> > > +	u64			slice;
> > > +	u64			vtime;
> > > +	u64			enq_flags;
> > > +};
> > 
> > With PATCH 2/4 introducing scx_bpf_task_set_slice() and
> > scx_bpf_task_set_dsq_vtime(), would it be reasonable to use those to set
> > these task properties and then completely get rid of these args in
> > scx_bpf_dsq_insert[_vtime]()?
> 
> Maybe. However, the most common usage pattern is setting vtime and slice on
> insertion, so I think it makes sense to have a shortcut interface for that.
> Even if the overhead difference is negligible, it's nice to have a dedicated
> interface for the most common use case.

Yes, after talking about this during office hours, I agree that it's useful
to be able to set both vtime and slice when inserting a task. While the
overhead is likely negligible, it could still impact hot paths, so:

Acked-by: Andrea Righi <arighi@nvidia.com>

Thanks,
-Andrea

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH 5/4] sched_ext/tools: Add compat wrapper for scx_bpf_task_set_slice/dsq_vtime()
  2025-10-07  1:51 [PATCHSET sched_ext/for-6.19] sched_ext: Misc changes with some prep patches for sub-sched support Tejun Heo
                   ` (3 preceding siblings ...)
  2025-10-07  1:51 ` [PATCH 4/4] sched_ext: Make scx_bpf_dsq_insert*() return bool Tejun Heo
@ 2025-10-07 19:06 ` Tejun Heo
  2025-10-13 18:53 ` [PATCHSET sched_ext/for-6.19] sched_ext: Misc changes with some prep patches for sub-sched support Tejun Heo
  5 siblings, 0 replies; 26+ messages in thread
From: Tejun Heo @ 2025-10-07 19:06 UTC (permalink / raw)
  To: David Vernet, Andrea Righi, Changwoo Min; +Cc: linux-kernel, sched-ext

for sub-scheduler authority checks. Add compat wrappers which fall back to
direct p->scx field writes on older kernels.

Suggested-by: Andrea Righi <arighi@nvidia.com>
Signed-off-by: Tejun Heo <tj@kernel.org>
---
 tools/sched_ext/include/scx/common.bpf.h |    2 --
 tools/sched_ext/include/scx/compat.bpf.h |   24 ++++++++++++++++++++++++
 2 files changed, 24 insertions(+), 2 deletions(-)

--- a/tools/sched_ext/include/scx/common.bpf.h
+++ b/tools/sched_ext/include/scx/common.bpf.h
@@ -101,8 +101,6 @@ s32 scx_bpf_pick_any_cpu_node(const cpum
 s32 scx_bpf_pick_any_cpu(const cpumask_t *cpus_allowed, u64 flags) __ksym;
 bool scx_bpf_task_running(const struct task_struct *p) __ksym;
 s32 scx_bpf_task_cpu(const struct task_struct *p) __ksym;
-bool scx_bpf_task_set_slice(struct task_struct *p, u64 slice) __ksym __weak;
-bool scx_bpf_task_set_dsq_vtime(struct task_struct *p, u64 vtime) __ksym __weak;
 struct rq *scx_bpf_cpu_rq(s32 cpu) __ksym;
 struct rq *scx_bpf_locked_rq(void) __ksym;
 struct task_struct *scx_bpf_cpu_curr(s32 cpu) __ksym __weak;
--- a/tools/sched_ext/include/scx/compat.bpf.h
+++ b/tools/sched_ext/include/scx/compat.bpf.h
@@ -235,6 +235,30 @@ scx_bpf_dsq_insert(struct task_struct *p
 }
 
 /*
+ * v6.19: scx_bpf_task_set_slice() and scx_bpf_task_set_dsq_vtime() added to for
+ * sub-sched authority checks. Drop the wrappers and move the decls to
+ * common.bpf.h after v6.22.
+ */
+bool scx_bpf_task_set_slice___new(struct task_struct *p, u64 slice) __ksym __weak;
+bool scx_bpf_task_set_dsq_vtime___new(struct task_struct *p, u64 vtime) __ksym __weak;
+
+static inline void scx_bpf_task_set_slice(struct task_struct *p, u64 slice)
+{
+	if (bpf_ksym_exists(scx_bpf_task_set_slice___new))
+		scx_bpf_task_set_slice___new(p, slice);
+	else
+		p->scx.slice = slice;
+}
+
+static inline void scx_bpf_task_set_dsq_vtime(struct task_struct *p, u64 vtime)
+{
+	if (bpf_ksym_exists(scx_bpf_task_set_dsq_vtime___new))
+		scx_bpf_task_set_dsq_vtime___new(p, vtime);
+	else
+		p->scx.dsq_vtime = vtime;
+}
+
+/*
  * Define sched_ext_ops. This may be expanded to define multiple variants for
  * backward compatibility. See compat.h::SCX_OPS_LOAD/ATTACH().
  */

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCHSET sched_ext/for-6.19] sched_ext: Misc changes with some prep patches for sub-sched support
  2025-10-07  1:51 [PATCHSET sched_ext/for-6.19] sched_ext: Misc changes with some prep patches for sub-sched support Tejun Heo
                   ` (4 preceding siblings ...)
  2025-10-07 19:06 ` [PATCH 5/4] sched_ext/tools: Add compat wrapper for scx_bpf_task_set_slice/dsq_vtime() Tejun Heo
@ 2025-10-13 18:53 ` Tejun Heo
  5 siblings, 0 replies; 26+ messages in thread
From: Tejun Heo @ 2025-10-13 18:53 UTC (permalink / raw)
  To: David Vernet, Andrea Righi, Changwoo Min; +Cc: linux-kernel, sched-ext

On Mon, Oct 06, 2025 at 03:51:43PM -1000, Tejun Heo wrote:
> Hello,
> 
> This patchset contains misc changes and some prep patches for future
> sub-scheduler support.
> 
> 0001-tools-sched_ext-Strip-compatibility-macros-for-cgrou.patch
> 0002-sched_ext-Add-scx_bpf_task_set_slice-and-scx_bpf_tas.patch
> 0003-sched_ext-Wrap-kfunc-args-in-struct-to-prepare-for-a.patch
> 0004-sched_ext-Make-scx_bpf_dsq_insert-return-bool.patch

Applied to sched_ext/for-6.19.

Thanks.

-- 
tejun

^ permalink raw reply	[flat|nested] 26+ messages in thread

end of thread, other threads:[~2025-10-13 18:53 UTC | newest]

Thread overview: 26+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-10-07  1:51 [PATCHSET sched_ext/for-6.19] sched_ext: Misc changes with some prep patches for sub-sched support Tejun Heo
2025-10-07  1:51 ` [PATCH 1/4] tools/sched_ext: Strip compatibility macros for cgroup and dispatch APIs Tejun Heo
2025-10-07  2:42   ` Emil Tsalapatis
2025-10-07  9:42   ` Andrea Righi
2025-10-07 16:22   ` Changwoo Min
2025-10-07  1:51 ` [PATCH 2/4] sched_ext: Add scx_bpf_task_set_slice() and scx_bpf_task_set_dsq_vtime() Tejun Heo
2025-10-07  2:56   ` Emil Tsalapatis
2025-10-07 18:09     ` Tejun Heo
2025-10-07  9:34   ` Andrea Righi
2025-10-07 18:09     ` Tejun Heo
2025-10-07 16:28   ` Changwoo Min
2025-10-07 18:11     ` Tejun Heo
2025-10-07  1:51 ` [PATCH 3/4] sched_ext: Wrap kfunc args in struct to prepare for aux__prog Tejun Heo
2025-10-07  9:48   ` Andrea Righi
2025-10-07 18:24     ` Tejun Heo
2025-10-07 18:37       ` Andrea Righi
2025-10-07 16:04   ` Emil Tsalapatis
2025-10-07 16:38   ` Changwoo Min
2025-10-07  1:51 ` [PATCH 4/4] sched_ext: Make scx_bpf_dsq_insert*() return bool Tejun Heo
2025-10-07  4:28   ` Emil Tsalapatis
2025-10-07  9:41   ` Andrea Righi
2025-10-07 15:03     ` Emil Tsalapatis
2025-10-07 17:25       ` Andrea Righi
2025-10-07 16:47   ` Changwoo Min
2025-10-07 19:06 ` [PATCH 5/4] sched_ext/tools: Add compat wrapper for scx_bpf_task_set_slice/dsq_vtime() Tejun Heo
2025-10-13 18:53 ` [PATCHSET sched_ext/for-6.19] sched_ext: Misc changes with some prep patches for sub-sched support Tejun Heo

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox