mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
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,

  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®