From: Andrea Righi <arighi@nvidia.com>
To: Tejun Heo <tj@kernel.org>
Cc: David Vernet <void@manifault.com>,
Changwoo Min <changwoo@igalia.com>,
sched-ext@lists.linux.dev, Emil Tsalapatis <emil@etsalapatis.com>,
linux-kernel@vger.kernel.org
Subject: Re: [PATCH sched_ext/for-7.3-fixes] sched_ext: scx_qmap: Fix pending partition work handoff
Date: Sun, 6 Sep 2026 16:02:23 +0200 [thread overview]
Message-ID: <ap1yb7oMEFeBNTPZ@gpd4> (raw)
In-Reply-To: <4c9a9c9cabc3547e23bae5ae00421a52@kernel.org>
Hi Tejun,
On Sat, Sep 05, 2026 at 12:53:44PM -1000, Tejun Heo wrote:
> qmap can leave partition work pending with no runner. The effective-cap
> callback publishes its request after failing to acquire part_busy, while
> redistribute() checks for pending work before releasing it. Either ordering
> can miss a request arriving as the current runner finishes, delaying the
> update until the round-robin timer runs.
>
> Publish requests before trying to become the runner and release part_busy
> before checking for more work. Have all holders drain pending requests after
> releasing it, including the stats flush. Distinguish mask refreshes from
> repartitions so an effective-cap update only rebuilds the partition when a
> repartition was also requested.
>
> Fixes: e9151ed5c944 ("tools/sched_ext: scx_qmap - Expand hierarchical sub-scheduling")
> Reported-by: Andrea Righi <arighi@nvidia.com>
> Signed-off-by: Tejun Heo <tj@kernel.org>
Looks good to me, thanks for fixing it.
Reviewed-by: Andrea Righi <arighi@nvidia.com>
-Andrea
> ---
> tools/sched_ext/scx_qmap.bpf.c | 75 +++++++++++++++++++++--------------------
> 1 file changed, 40 insertions(+), 35 deletions(-)
>
> --- a/tools/sched_ext/scx_qmap.bpf.c
> +++ b/tools/sched_ext/scx_qmap.bpf.c
> @@ -1295,11 +1295,16 @@ struct {
> __type(value, struct round_robin_timer);
> } round_robin_timer SEC(".maps");
>
> +enum part_pending_flags {
> + PART_REFRESH = BIT_U64(0),
> + PART_REDISTRIBUTE = BIT_U64(1),
> +};
> +
> /*
> * Partition update synchronization. qa.part can be written from concurrent
> * contexts. This single-runner guard admits one writer at a time without
> * holding a lock across the grant/revoke kfuncs. part_pending coalesces
> - * repartition requests that arrive while it is held.
> + * refresh and repartition requests that arrive while it is held.
> *
> * They live in .bss, not the arena: rr_advance() runs from a bpf_timer
> * callback, where the verifier rejects atomic ops on arena memory.
> @@ -1668,33 +1673,46 @@ __noinline void apply_partition(void)
> }
> }
>
> -/*
> - * Recompute the split off the node's held caps and apply it. The contexts this
> - * runs from (the sub-sched and cgroup callbacks, the rr timer) are not
> - * serialized by the kernel, so a single runner does the work. A caller that
> - * finds the guard held leaves part_pending set; the holder drains it before
> - * releasing, with the rr timer as a backstop.
> +/**
> + * execute_partition - Run pending partition updates
> + *
> + * The rr timer is the backstop if the loop reaches its iteration limit.
> */
> -static void redistribute(void)
> +static void execute_partition(void)
> {
> + u64 pending;
> s32 i;
>
> - __sync_fetch_and_or(&part_pending, 1);
> + bpf_for(i, 0, 1024) {
> + if (!part_try_start())
> + break;
>
> - if (!part_try_start())
> - return;
> + pending = __sync_fetch_and_and(&part_pending, 0);
> + if (pending & PART_REDISTRIBUTE) {
> + /* charge elapsed time before repartitioning */
> + account_alloc();
> + compute_partition();
> + apply_partition();
> + } else if (pending & PART_REFRESH) {
> + refresh_usable();
> + }
>
> - bpf_for(i, 0, 1024) {
> - __sync_fetch_and_and(&part_pending, 0);
> - /* charge elapsed time to the current partition before rebuilding it */
> - account_alloc();
> - compute_partition();
> - apply_partition();
> + /*
> + * Requests are published before trying the guard. Releasing it
> + * before checking pending work ensures a racing request is
> + * either observed here or handled by a caller that acquires the
> + * guard.
> + */
> + part_end();
> if (!__sync_fetch_and_or(&part_pending, 0))
> break;
> }
> +}
>
> - part_end();
> +static void redistribute(void)
> +{
> + __sync_fetch_and_or(&part_pending, PART_REDISTRIBUTE);
> + execute_partition();
> }
>
> /*
> @@ -1708,6 +1726,7 @@ int flush_alloc(void *ctx)
> if (part_try_start()) {
> account_alloc();
> part_end();
> + execute_partition();
> }
> return 0;
> }
> @@ -1765,9 +1784,7 @@ static void rr_advance(void)
>
> part_end();
>
> - /* a resplit queued while we held the guard supersedes this rotation */
> - if (__sync_fetch_and_or(&part_pending, 0))
> - redistribute();
> + execute_partition();
> }
>
> /* advance the time-shared cid pool every round_robin_ns */
> @@ -2041,20 +2058,8 @@ void BPF_STRUCT_OPS(qmap_sub_ecaps_updat
> cmask_clear(cid, &qa.avail_cids.mask);
> }
>
> - /*
> - * When another runner holds the partition guard, set part_pending:
> - * redistribute() drains it before releasing and rr_advance() checks it
> - * after, so the deferred refresh lands by the next rr tick. A
> - * repartition that lost the guard to us runs here.
> - */
> - if (part_try_start()) {
> - refresh_usable();
> - part_end();
> - if (__sync_fetch_and_or(&part_pending, 0))
> - redistribute();
> - } else {
> - __sync_fetch_and_or(&part_pending, 1);
> - }
> + __sync_fetch_and_or(&part_pending, PART_REFRESH);
> + execute_partition();
> }
>
> SCX_OPS_CID_DEFINE(qmap_ops,
next prev parent reply other threads:[~2026-09-06 14:02 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-05 22:53 Tejun Heo
2026-09-06 14:02 ` Andrea Righi [this message]
2026-09-06 22:40 ` Tejun Heo
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=ap1yb7oMEFeBNTPZ@gpd4 \
--to=arighi@nvidia.com \
--cc=changwoo@igalia.com \
--cc=emil@etsalapatis.com \
--cc=linux-kernel@vger.kernel.org \
--cc=sched-ext@lists.linux.dev \
--cc=tj@kernel.org \
--cc=void@manifault.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®