The Linux Kernel Mailing List
 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 1/5] sched_ext: Make exit claiming lock-free
Date: Mon, 27 Jul 2026 21:35:12 +0200	[thread overview]
Message-ID: <amey8FunQb8M7qwI@gpd4> (raw)
In-Reply-To: <20260725005019.1297049-2-tj@kernel.org>

Hi Tejun,

On Fri, Jul 24, 2026 at 02:50:15PM -1000, Tejun Heo wrote:
> scx_claim_exit() claims descendants' exits by walking the subtree under
> scx_sched_lock, making exit claiming, and thus scx_error(), unusable from
> NMI and from under scx_sched_lock. However, kfuncs raising errors can run
> from NMI-attached BPF progs, the hardlockup handler runs in NMI, and
> scx_link_sched() wants to report failures under the lock.
> 
> The walk does two things with different urgencies: ->aborting must be
> asserted synchronously to break IRQs-off dispatch-path live-locks, while the
> descendants' exit_kind claims can happen later. Split them: sweep ->aborting
> locklessly under RCU to unwedge the system and defer the locked
> SCX_EXIT_PARENT walk to a new irq_work, both of which are NMI-safe.
> 
> The sweep stores each node's ->aborting and then reads its children list
> while scx_link_sched() inserts and then checks the parent's ->aborting, the
> two sides paired by full barriers - one side always sees the other. A link
> that sees ->aborting undoes its insert and fails. As the undo's
> list_del_rcu() leaves ->sibling non-empty, list_empty() can no longer
> identify a never-linked sched during teardown - add sch->linked instead.
> 
> trace_sched_ext_exit can now fire from NMI. The exit backtrace is skipped
> for NMI exits as stack_trace_save()'s NMI-safety is arch-dependent and
> undocumented.
> 
> Signed-off-by: Tejun Heo <tj@kernel.org>
> ---

...

> diff --git a/kernel/sched/ext/ext.c b/kernel/sched/ext/ext.c
> index aca8d2380509..30ce4c9428cf 100644
> --- a/kernel/sched/ext/ext.c
> +++ b/kernel/sched/ext/ext.c
> @@ -5027,6 +5027,7 @@ static void scx_sched_free_rcu_work(struct work_struct *work)

...

>  /*
>   * Claim the exit on @sch. The caller must ensure that the helper kthread work
>   * is kicked before the current task can be preempted. Once exit_kind is
>   * claimed, scx_error() can no longer trigger, so if the current task gets
>   * preempted and the BPF scheduler fails to schedule it back, the helper work
>   * will never be kicked and the whole system can wedge.
> + *
> + * Lock-free and safe to call from any context including NMI.
>   */
>  static bool scx_claim_exit(struct scx_sched *sch, enum scx_exit_kind kind)
>  {
> @@ -6279,35 +6310,28 @@ static bool scx_claim_exit(struct scx_sched *sch, enum scx_exit_kind kind)
>  	if (!atomic_try_cmpxchg(&sch->exit_kind, &none, kind))
>  		return false;
>  
> -	/*
> -	 * Some CPUs may be trapped in the dispatch paths. Set the aborting
> -	 * flag to break potential live-lock scenarios, ensuring we can
> -	 * successfully reach scx_bypass().
> -	 */
> -	WRITE_ONCE(sch->aborting, true);
> -
>  	trace_sched_ext_exit(sch, kind);
>  
> -	/*
> -	 * Propagate exits to descendants immediately. Each has a dedicated
> -	 * helper kthread and can run in parallel. While most of disabling is
> -	 * serialized, running them in separate threads allows parallelizing
> -	 * ops.exit(), which can take arbitrarily long prolonging bypass mode.
> -	 *
> -	 * To guarantee forward progress, this propagation must be in-line so
> -	 * that ->aborting is synchronously asserted for all sub-scheds. The
> -	 * propagation is also the interlocking point against sub-sched
> -	 * attachment. See scx_link_sched().
> -	 *
> -	 * This doesn't cause recursions as propagation only takes place for
> -	 * non-propagation exits.
> -	 */
> -	if (kind != SCX_EXIT_PARENT) {
> -		scoped_guard (raw_spinlock_irqsave, &scx_sched_lock) {
> -			struct scx_sched *pos;
> +	if (kind == SCX_EXIT_PARENT) {
> +		/* an ancestor is already sweeping the subtree */
> +		WRITE_ONCE(sch->aborting, true);
> +	} else {
> +		struct scx_sched *pos;
> +
> +		/*
> +		 * CPUs may be live-locked in the dispatch paths of @sch or its
> +		 * descendants, which ->aborting breaks. Sweep the subtree
> +		 * locklessly so that this works from NMI. smp_store_mb() orders
> +		 * each node's ->aborting store before its children are walked -
> +		 * either we see a racing scx_link_sched() on ->children or it
> +		 * sees ->aborting.
> +		 */
> +		scoped_guard (rcu) {
>  			scx_for_each_descendant_pre(pos, sch)
> -				scx_disable(pos, SCX_EXIT_PARENT);
> +				smp_store_mb(pos->aborting, true);
>  		}
> +
> +		irq_work_queue(&sch->propagate_exit_irq_work);
>  	}

Should we move the trace_sched_ext_exit() after this block?

Before this patch, sch->aborting was set before the tracepoint. Now the
tracepoint callbacks run before any scheduler in the subtree is marked aborting.
Patch 4 also makes this path callable directly from the hardlockup NMI.

While the tracepoint is running, other CPUs may remain in the live-lock-prone
dispatch paths instead of observing ->aborting and backing out. Probably it
doesn't really matter much, but this should help reduce the recovery window a
bit.

Thanks,
-Andrea

  reply	other threads:[~2026-07-27 19:35 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-25  0:50 [PATCHSET sched_ext/for-7.3] sched_ext: NMI-safe exit handling Tejun Heo
2026-07-25  0:50 ` [PATCH 1/5] sched_ext: Make exit claiming lock-free Tejun Heo
2026-07-27 19:35   ` Andrea Righi [this message]
2026-07-27 20:36   ` [PATCH v2 " Tejun Heo
2026-07-25  0:50 ` [PATCH 2/5] sched_ext: Format bstr exit messages after claiming the exit Tejun Heo
2026-07-25  0:50 ` [PATCH 3/5] sched_ext: Report NMI kicks with scx_error() Tejun Heo
2026-07-25  0:50 ` [PATCH 4/5] sched_ext: Abort directly from the hardlockup handler Tejun Heo
2026-07-25  0:50 ` [PATCH 5/5] sched_ext: Report scx_link_sched() failures inline Tejun Heo
2026-07-27 21:17 ` [PATCHSET sched_ext/for-7.3] sched_ext: NMI-safe exit handling Andrea Righi
2026-07-27 21:24 ` 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=amey8FunQb8M7qwI@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