All of lore.kernel.org
 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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.