BPF List
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Tao Cui" <cui.tao@linux.dev>
Cc: sched-ext@lists.linux.dev, bpf@vger.kernel.org
Subject: Re: [PATCH 6/6] sched_ext: Clear the built-in idle masks on CPU hotplug transitions
Date: Thu, 12 Nov 2026 13:32:41 +0000	[thread overview]
Message-ID: <sashiko-outbox-211192@kernel.org> (raw)
In-Reply-To: <20261112130934.563321-7-cui.tao@linux.dev>

Thank you for your contribution! Sashiko AI review found 2 potential
issues to consider:
- [Medium] sched_ext: offline CPU re-sets idle mask bit after
  scx_idle_clear_cpu()
- [Medium] sched_ext: scx_idle_test_and_clear_cpu() claims inactive CPUs
  during hotplug
It also noticed 1 related pre-existing issue this patch does not
introduce:
- [Medium] sched_ext: data race on shared idle_smts mask in
  scx_idle_test_and_clear_cpu() [1]
--

commit 0e2a7b76afc726a460e91d0e19897631e59a961f
Author: Tao Cui <cuitao@kylinos.cn>

sched_ext: Clear the built-in idle masks on CPU hotplug transitions

This commit clears a hotplugged CPU from the built-in idle masks in
handle_hotplug() and rejects offline CPUs in scx_idle_test_and_clear_cpu().

> diff --git a/kernel/sched/ext/ext.c b/kernel/sched/ext/ext.c
> index 7d7e2a2fc5ae8..984d9224ab59c 100644
> --- a/kernel/sched/ext/ext.c
> +++ b/kernel/sched/ext/ext.c
> @@ -4358,6 +4358,13 @@ static void handle_hotplug(struct rq *rq, bool online)
>  	if (scx_enabled())
>  		scx_idle_update_selcpu_topology(&sch->ops);
>  
> +	/*
> +	 * Keep the built-in idle masks in sync with the hotplug state: an
> +	 * offline CPU must stop being advertised as idle and a CPU coming
> +	 * back must not inherit a stale idle bit.
> +	 */
> +	scx_idle_clear_cpu(cpu);

[Severity: Medium]
Does the dying CPU re-set its bit in idle_cpus right after
scx_idle_clear_cpu() clears it?

During CPU teardown, handle_hotplug() runs at CPUHP_AP_ACTIVE, before
take_cpu_down() runs at CPUHP_TEARDOWN_CPU and parks migration/N.  When
migration/N parks and switches the dying CPU back to rq->idle so do_idle()
can halt it, set_next_task_idle() -> __scx_update_idle() calls
update_builtin_idle(cpu, true), which does not check whether the CPU or
runqueue is online and sets the bit in idle_cpus again.

Because normal tasks have their affinity restricted to online CPUs and BPF
schedulers typically pass task affinities to scx_bpf_pick_idle_cpu(), the
claim path in scx_idle_test_and_clear_cpu() is not reached for the offline
CPU.  Read-only consumers such as scx_bpf_get_idle_cpumask() and the
!cpumask_empty(idle_cpumask(waker_node)->cpu) check in scx_select_cpu_dfl()
therefore still see the offline CPU marked idle for the entire offline
window.  Gating idle=true updates in __scx_update_idle() or
update_builtin_idle() on the CPU/rq online state would prevent the dying
CPU from re-setting the bit.

> diff --git a/kernel/sched/ext/idle.c b/kernel/sched/ext/idle.c
> index 922fbc3065ccf..ff0c5402886e6 100644
> --- a/kernel/sched/ext/idle.c
> +++ b/kernel/sched/ext/idle.c
> @@ -107,6 +107,18 @@ static bool scx_idle_test_and_clear_cpu(int cpu)
>  			__cpumask_clear_cpu(cpu, idle_smts);
>  	}

[Severity: Medium]
This problem wasn't introduced by this patch, but nothing serializes
[1] concurrent updates to the shared idle_smts mask in
scx_idle_test_and_clear_cpu().  Both cpumask_andnot() and
__cpumask_clear_cpu() perform non-atomic read-modify-write operations on
the bitmap words:

CPU0                                CPU1
scx_idle_test_and_clear_cpu()       scx_idle_test_and_clear_cpu()
  cpumask_andnot()                    cpumask_andnot()
    val = *word;                        val = *word;
    val &= ~smt0;                       val &= ~smt1;
    *word = val;                        *word = val;  <-- CPU0 clear lost

A lost clear leaves a core that is no longer wholly idle marked in
idle_smts, causing SMT-aware idle selection to place tasks on busy sibling
threads instead of idle cores.

> +
> +	/*
> +	 * An offline CPU is never an idle candidate, but its bit can
> +	 * linger past @cpu going offline: the dying CPU keeps re-picking
> +	 * its idle task until it halts, which can happen after the
> +	 * hotplug paths have already run. Drop the stale bit and refuse
> +	 * the claim.
> +	 */
> +	if (unlikely(!cpu_online(cpu))) {
> +		cpumask_clear_cpu(cpu, idle_cpus);
> +		return false;
> +	}
> +
>  	return cpumask_test_and_clear_cpu(cpu, idle_cpus);
>  }

[Severity: Medium]
Can scx_idle_test_and_clear_cpu() still claim a CPU while it is inactive
during hotplug transitions?

On teardown, sched_cpu_deactivate() clears cpu_active(cpu) and
handle_hotplug() clears SCX_RQ_ONLINE at CPUHP_AP_ACTIVE, while
cpu_online(cpu) stays true until __cpu_disable() runs at
CPUHP_TEARDOWN_CPU.  Likewise on bringup, cpu_online(cpu) is set before the
CPU reaches CPUHP_AP_ACTIVE and sets cpu_active(cpu) and SCX_RQ_ONLINE.  If
cpuhp/N blocks during either window (for example in synchronize_rcu() or a
sleepable ops.cpu_offline() / ops.cpu_online() callback), switching to
rq->idle marks the CPU in idle_cpus, and scx_idle_test_and_clear_cpu() will
allow claiming it because cpu_online(cpu) is true.  select_task_rq() then
rejects the pick via !is_cpu_allowed() (which requires cpu_active(cpu) for
non-kthreads) and falls back with SCX_EV_SELECT_CPU_FALLBACK.  Checking
cpu_active(cpu) (or scx_rq_online(cpu_rq(cpu))) here would avoid claiming
CPUs that cannot accept tasks yet.

[1] https://sashiko.dev/#/bug/linux-ca6a3761-220e-4ce4-924a-d7356268acdd

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261112130934.563321-1-cui.tao@linux.dev?part=6

  reply	other threads:[~2026-11-12 13:32 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-12 13:09 [PATCH 0/6] sched_ext: fix kfunc, sub-sched, flatcg and idle-mask issues Tao Cui
2026-11-12 13:09 ` [PATCH 1/6] sched_ext: Reject DSQ iterator kfuncs in tracing programs Tao Cui
2026-11-12 17:34   ` Tejun Heo
2026-11-12 13:09 ` [PATCH 2/6] sched_ext: Make scx_bpf_cid_node() a benign lookup for invalid cids Tao Cui
2026-11-12 17:34   ` Tejun Heo
2026-11-12 13:09 ` [PATCH 3/6] sched_ext: Return -EBUSY from a pre-init scx_bpf_sub_caps() read Tao Cui
2026-11-12 17:34   ` Tejun Heo
2026-11-12 13:09 ` [PATCH 4/6] sched_ext: Reject cid_online/cid_offline on sub-schedulers Tao Cui
2026-11-12 17:34   ` Tejun Heo
2026-11-12 13:09 ` [PATCH 5/6] tools/sched_ext: scx_flatcg: Don't strand a cgroup on the ENQ_RACE path Tao Cui
2026-11-12 13:26   ` sashiko-bot
2026-11-12 17:34   ` Tejun Heo
2026-11-12 13:09 ` [PATCH 6/6] sched_ext: Clear the built-in idle masks on CPU hotplug transitions Tao Cui
2026-11-12 13:32   ` sashiko-bot [this message]
2026-11-12 17:34   ` Tejun Heo
2026-11-12 17:34 ` [PATCH 0/6] sched_ext: fix kfunc, sub-sched, flatcg and idle-mask issues 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=sashiko-outbox-211192@kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=cui.tao@linux.dev \
    --cc=sashiko-reviews@lists.linux.dev \
    --cc=sched-ext@lists.linux.dev \
    /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