* [PATCH v3 0/2] sched_ext: document and enforce vtime ordering constraints
@ 2026-09-02 2:48 Tao Cui
2026-09-02 2:48 ` [PATCH v3 1/2] sched_ext: document the rolling-cursor requirement for dsq_vtime Tao Cui
` (2 more replies)
0 siblings, 3 replies; 5+ messages in thread
From: Tao Cui @ 2026-09-02 2:48 UTC (permalink / raw)
To: tj
Cc: void, arighi, changwoo, michalblk, liwanwu, sched-ext,
linux-kernel, bpf, cui.tao, Tao Cui
From: Tao Cui <cuitao@kylinos.cn>
Patch 1 documents the rolling-cursor requirement for vtime ordering in
scx_bpf_dsq_insert_vtime(). Patch 2 fixes scx_flatcg's comparator to
use the cyclic comparison, which is correct there because
cgrp_cap_budget() upholds that requirement.
Changes since v2:
- 1/2: "less than 2^63 apart" (not "within"), folded into the paragraph
above
- 2/2: use time_before() instead of open-coded comparison, drop the
comment, fix the wrap direction and timing, state both lag and lead
bounds, Fixes corrected to upstream a4103eacc2ab (Tejun)
Changes since v1:
- drop 1/2 (kernel priq comparator change): the cyclic ordering is
the documented contract; a plain comparison causes unbounded
starvation at the natural wrap (Andrea, Tejun)
- new 1/2: document the rolling-cursor requirement instead
- 2/2 (flatcg) unchanged
Tao Cui (2):
sched_ext: document the rolling-cursor requirement for dsq_vtime
sched_ext/scx_flatcg: make cgv_node_less() wraparound-safe
kernel/sched/ext/ext.c | 4 +++-
tools/sched_ext/scx_flatcg.bpf.c | 2 +-
2 files changed, 4 insertions(+), 2 deletions(-)
--
2.43.0
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v3 1/2] sched_ext: document the rolling-cursor requirement for dsq_vtime
2026-09-02 2:48 [PATCH v3 0/2] sched_ext: document and enforce vtime ordering constraints Tao Cui
@ 2026-09-02 2:48 ` Tao Cui
2026-09-02 2:48 ` [PATCH v3 2/2] sched_ext/scx_flatcg: make cgv_node_less() wraparound-safe Tao Cui
2026-09-02 6:42 ` [PATCH v3 0/2] sched_ext: document and enforce vtime ordering constraints Tejun Heo
2 siblings, 0 replies; 5+ messages in thread
From: Tao Cui @ 2026-09-02 2:48 UTC (permalink / raw)
To: tj
Cc: void, arighi, changwoo, michalblk, liwanwu, sched-ext,
linux-kernel, bpf, cui.tao, Tao Cui
From: Tao Cui <cuitao@kylinos.cn>
scx_bpf_dsq_insert_vtime() orders tasks by time_before64(), which is
only meaningful when the values within a given DSQ stay less than 2^63
apart. This is implicit in how a vtime scheduler works but not spelled
out anywhere. Document it so BPF scheduler authors know the
constraint.
Signed-off-by: Tao Cui <cuitao@kylinos.cn>
---
kernel/sched/ext/ext.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/kernel/sched/ext/ext.c b/kernel/sched/ext/ext.c
index 8041c87a3562..81a506a4c8ab 100644
--- a/kernel/sched/ext/ext.c
+++ b/kernel/sched/ext/ext.c
@@ -8903,7 +8903,9 @@ struct scx_bpf_dsq_insert_vtime_args {
*
* @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.
+ * ordering and vice-versa. vtime is a rolling cursor and values used for
+ * ordering within a given DSQ should stay less than 2^63 apart for
+ * time_before64() ordering to remain well-defined.
*
* 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
--
2.43.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH v3 2/2] sched_ext/scx_flatcg: make cgv_node_less() wraparound-safe
2026-09-02 2:48 [PATCH v3 0/2] sched_ext: document and enforce vtime ordering constraints Tao Cui
2026-09-02 2:48 ` [PATCH v3 1/2] sched_ext: document the rolling-cursor requirement for dsq_vtime Tao Cui
@ 2026-09-02 2:48 ` Tao Cui
2026-09-02 3:03 ` sashiko-bot
2026-09-02 6:42 ` [PATCH v3 0/2] sched_ext: document and enforce vtime ordering constraints Tejun Heo
2 siblings, 1 reply; 5+ messages in thread
From: Tao Cui @ 2026-09-02 2:48 UTC (permalink / raw)
To: tj
Cc: void, arighi, changwoo, michalblk, liwanwu, sched-ext,
linux-kernel, bpf, cui.tao, Tao Cui, Sashiko
From: Tao Cui <cuitao@kylinos.cn>
cgv_node_less() compares cvtimes with a plain <, which misorders once
cvtime wraps: the wrapped node lands at the front of the tree while
the unwrapped ones get stuck behind it. Each CPU picking a cgroup
charges it a full slice, making wrap occur earlier than a naive
estimate might suggest.
Use time_before() instead. cgrp_cap_budget() bounds the lag behind
cvtime_now, while the lead is bounded by the slice charge plus pending
cvtime_delta on re-insertion, so the cyclic ordering assumptions of
time_before() hold.
Fixes: a4103eacc2ab ("sched_ext: Add a cgroup scheduler which uses flattened hierarchy")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Link: https://lore.kernel.org/r/3f1ce004-e259-4e72-a5f7-14a5050053bd@linux.dev
Signed-off-by: Tao Cui <cuitao@kylinos.cn>
---
tools/sched_ext/scx_flatcg.bpf.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/sched_ext/scx_flatcg.bpf.c b/tools/sched_ext/scx_flatcg.bpf.c
index 454ebb820c5e..5e6abd0bccb3 100644
--- a/tools/sched_ext/scx_flatcg.bpf.c
+++ b/tools/sched_ext/scx_flatcg.bpf.c
@@ -144,7 +144,7 @@ static bool cgv_node_less(struct bpf_rb_node *a, const struct bpf_rb_node *b)
cgc_a = container_of(a, struct cgv_node, rb_node);
cgc_b = container_of(b, struct cgv_node, rb_node);
- return cgc_a->cvtime < cgc_b->cvtime;
+ return time_before(cgc_a->cvtime, cgc_b->cvtime);
}
static struct fcg_cpu_ctx *find_cpu_ctx(void)
--
2.43.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH v3 2/2] sched_ext/scx_flatcg: make cgv_node_less() wraparound-safe
2026-09-02 2:48 ` [PATCH v3 2/2] sched_ext/scx_flatcg: make cgv_node_less() wraparound-safe Tao Cui
@ 2026-09-02 3:03 ` sashiko-bot
0 siblings, 0 replies; 5+ messages in thread
From: sashiko-bot @ 2026-09-02 3:03 UTC (permalink / raw)
To: Tao Cui; +Cc: sched-ext, bpf
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
Pre-existing issues:
- [High] Unsigned division on a wrapped negative time delta causes massive artificial inflation of virtual time for expired cgroups.
- [Medium] Race condition in cvtime_delta extraction using __sync_fetch_and_sub(ptr, *ptr) causes double accounting.
--
commit 069998f7546e450b1de3ae56c137b9e1dd16b919
Author: Tao Cui <cuitao@kylinos.cn>
sched_ext/scx_flatcg: make cgv_node_less() wraparound-safe
cgv_node_less() compares cvtimes with a plain <, which misorders once
cvtime wraps: the wrapped node lands at the front of the tree while
the unwrapped ones get stuck behind it. Each CPU picking a cgroup
charges it a full slice, making wrap occur earlier than a naive
estimate might suggest.
Link: https://lore.kernel.org/r/3f1ce004-e259-4e72-a5f7-14a5050053bd@linux.dev
> diff --git a/tools/sched_ext/scx_flatcg.bpf.c b/tools/sched_ext/scx_flatcg.bpf.c
> index fec3595818269..acc1995630e6d 100644
> --- a/tools/sched_ext/scx_flatcg.bpf.c
> +++ b/tools/sched_ext/scx_flatcg.bpf.c
[ ... ]
> @@ -144,7 +144,7 @@ static bool cgv_node_less(struct bpf_rb_node *a, const struct bpf_rb_node *b)
> cgc_a = container_of(a, struct cgv_node, rb_node);
> cgc_b = container_of(b, struct cgv_node, rb_node);
>
> - return cgc_a->cvtime < cgc_b->cvtime;
> + return time_before(cgc_a->cvtime, cgc_b->cvtime);
> }
While reviewing this file, I noticed a couple of pre-existing issues:
tools/sched_ext/scx_flatcg.bpf.c:cgrp_cap_budget() {
...
delta = __sync_fetch_and_sub(&cgc->cvtime_delta, cgc->cvtime_delta);
cvtime = cgv_node->cvtime + delta;
...
}
[Severity: Medium]
This isn't a bug introduced by this patch, but does this create a race condition
that leads to double accounting?
Because __sync_fetch_and_sub(ptr, *ptr) evaluates the second argument before
the atomic subtraction, a concurrent __sync_fetch_and_add() from another CPU
between the memory read of cgc->cvtime_delta and the atomic subtraction
will cause the added delta to be subtracted but still partially left in the
counter. The atomic operation returns the new value, charging the cgroup for
the increment, but leaves the increment in the counter to be charged again on
the next extraction.
If CPU A executes fcg_stopping() or fcg_dispatch() and calls
__sync_fetch_and_add(&cgc->cvtime_delta, val), and concurrently CPU B
executes cgrp_cap_budget() and evaluates
__sync_fetch_and_sub(&cgc->cvtime_delta, cgc->cvtime_delta), a race in the
tiny window between B's argument evaluation and the atomic subtraction could
trigger double charging.
Could this be replaced with an atomic exchange (e.g.,
__sync_lock_test_and_set()) to safely extract and clear the counter?
tools/sched_ext/scx_flatcg.bpf.c:fcg_dispatch() {
...
bpf_spin_lock(&cgv_tree_lock);
__sync_fetch_and_add(&cgc->cvtime_delta,
(cpuc->cur_at + cgrp_slice_ns - now) *
FCG_HWEIGHT_ONE / (cgc->hweight ?: 1));
bpf_spin_unlock(&cgv_tree_lock);
...
}
[Severity: High]
This isn't a bug introduced by this patch, but does this calculation suffer from
unsigned division on a wrapped negative time delta?
When a cgroup's slice has expired, the current time 'now' can easily be greater
than 'cpuc->cur_at + cgrp_slice_ns' due to interrupt latency or normal
scheduling jitter. The '(cpuc->cur_at + cgrp_slice_ns - now)' is computed using
unsigned u64 arithmetic, resulting in a wrapped large positive number. Since
all operands are unsigned and hweight is a u32, the subsequent multiplication
and division execute as unsigned arithmetic.
The resulting huge positive quotient is then added to cgc->cvtime_delta,
artificially inflating the virtual time by a massive amount and potentially
starving all tasks within the cgroup.
Should there be an explicit cast to a signed type (like s64) before division
to prevent this?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260902024812.794879-1-cui.tao@linux.dev?part=2
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v3 0/2] sched_ext: document and enforce vtime ordering constraints
2026-09-02 2:48 [PATCH v3 0/2] sched_ext: document and enforce vtime ordering constraints Tao Cui
2026-09-02 2:48 ` [PATCH v3 1/2] sched_ext: document the rolling-cursor requirement for dsq_vtime Tao Cui
2026-09-02 2:48 ` [PATCH v3 2/2] sched_ext/scx_flatcg: make cgv_node_less() wraparound-safe Tao Cui
@ 2026-09-02 6:42 ` Tejun Heo
2 siblings, 0 replies; 5+ messages in thread
From: Tejun Heo @ 2026-09-02 6:42 UTC (permalink / raw)
To: Tao Cui
Cc: void, arighi, changwoo, michalblk, liwanwu, sched-ext,
linux-kernel, bpf, Tao Cui
On Wed, Sep 02, 2026 at 10:48:10AM +0800, Tao Cui wrote:
> Tao Cui (2):
> sched_ext: document the rolling-cursor requirement for dsq_vtime
> sched_ext/scx_flatcg: make cgv_node_less() wraparound-safe
Applied 1-2 to sched_ext/for-7.4 with the subjects capitalized.
Thanks.
--
tejun
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-09-02 6:42 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-02 2:48 [PATCH v3 0/2] sched_ext: document and enforce vtime ordering constraints Tao Cui
2026-09-02 2:48 ` [PATCH v3 1/2] sched_ext: document the rolling-cursor requirement for dsq_vtime Tao Cui
2026-09-02 2:48 ` [PATCH v3 2/2] sched_ext/scx_flatcg: make cgv_node_less() wraparound-safe Tao Cui
2026-09-02 3:03 ` sashiko-bot
2026-09-02 6:42 ` [PATCH v3 0/2] sched_ext: document and enforce vtime ordering constraints Tejun Heo
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox