Linux virtualization list
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Shrikanth Hegde" <sshegde@linux.ibm.com>
Cc: "Eugenio Perez" <eperezma@redhat.com>,
	virtualization@lists.linux.dev,
	"Michael S. Tsirkin" <mst@redhat.com>
Subject: Re: [PATCH v14 06/13] sched/core: Try to use a preferred CPU in is_cpu_allowed
Date: Mon, 28 Sep 2026 06:00:02 +0000	[thread overview]
Message-ID: <20260928060002.C0D711F000FF@smtp.kernel.org> (raw)
In-Reply-To: <20260928053728.797539-7-sshegde@linux.ibm.com>

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] sched/core: O(N^2) wakeup latency and task clumping in fallback path
- [High] sched/fair: Active load balancing to non-preferred CPUs silently fails
- [High] sched/core: TOCTOU race with CPU hotplug breaks task affinity
--

commit dfa0f159ec643e02807bc453bbfcc49c9f1e7915
Author: Shrikanth Hegde <sshegde@linux.ibm.com>

sched/core: Try to use a preferred CPU in is_cpu_allowed

This commit modifies the scheduler to preferentially select preferred CPUs
when checking if a task is allowed to run on a given CPU. It introduces a
helper function to check if a task can migrate to a preferred CPU based on
its affinity mask.

> For the majority of cases, this would still keep select_fallback_rq()
> as O(N). cpumask_intersects_and(), which is O(N), is called only if
> !cpu_preferred. The task running there is expected to move out.
> Subsequently, it should run on a preferred CPU. This becomes O(N**2)
> only for tasks pinned solely to non-preferred CPUs. That is a rare case.

Is this description accurate?

Because the fallback loop iterates over the affinity mask sequentially, if
the allowed preferred CPUs happen to have higher indices than the
non-preferred CPUs, the loop will perform the intersection operation for
every non-preferred CPU it checks. This means any task with preferred CPUs
at higher indices could experience the quadratic latency overhead, rather
than only tasks pinned solely to non-preferred CPUs.

> diff --git a/kernel/sched/core.c b/kernel/sched/core.c
> index 0183c75d7d518..04400f934cc72 100644
> --- a/kernel/sched/core.c
> +++ b/kernel/sched/core.c
[ ... ]
> @@ -2504,6 +2504,24 @@ static inline bool rq_has_pinned_tasks(struct rq *rq)
>  	return rq->nr_pinned;
>  }
>  
> +static inline bool task_can_migrate_to_preferred(struct task_struct *p, int cpu)
> +{
> +	/* No need to migrate from a preferred CPU */
> +	if (cpu_preferred(cpu))
> +		return false;
> +
> +	/* Only FAIR tasks honor preferred CPU state */
> +	if (unlikely(p->sched_class != &fair_sched_class))
> +		return false;
> +
> +	/* Ignore preferred state if task affinity is changing */
> +	if (unlikely(!cpumask_test_cpu(task_cpu(p), p->cpus_ptr)))
> +		return false;
> +
> +	return cpumask_intersects_and(p->cpus_ptr, cpu_preferred_mask,
> +				      task_cpu_possible_mask(p));
> +}

[Severity: High]
Does this intersection operation lead to quadratic latency during wakeups
when combined with the fallback loop?

When select_task_rq() in kernel/sched/core.c picks a non-preferred CPU
because it is idle, is_cpu_allowed() will reject it, forcing the task into
select_fallback_rq(). The fallback loop iterates sequentially over all CPUs:

kernel/sched/core.c:select_fallback_rq() {
    ...
    for_each_cpu(dest_cpu, p->cpus_ptr) {
        if (!is_cpu_allowed(p, dest_cpu))
            continue;
        ...
        goto out;
    }
    ...
}

If the allowed preferred CPUs are at the end of the cpumask, wouldn't this
perform an intersection for every non-preferred CPU it checks, leading to
severe scheduling latency? Additionally, wouldn't this deterministic loop
always dump the task on the first preferred CPU it finds, destroying load
distribution by clumping tasks on the lowest-ID preferred CPU?

This performance degradation from wakeups on non-preferred CPUs does not
appear to be resolved in the final state of the patch series.

[ ... ]
> @@ -2519,8 +2537,12 @@ static inline bool is_cpu_allowed(struct task_struct *p, int cpu)
>  		return cpu_online(cpu);
>  
>  	/* Non kernel threads are not allowed during either online or offline. */
> -	if (!(p->flags & PF_KTHREAD))
> +	if (!(p->flags & PF_KTHREAD)) {
> +		/* Try to use preferred CPU if task's affinity allows */
> +		if (task_can_migrate_to_preferred(p, cpu))
> +			return false;

[Severity: High]
Could returning false for non-preferred CPUs here cause active load
balancing to silently fail?

During routine background load balancing, if the system attempts to pull
load from a preferred CPU to an idle non-preferred CPU, the stopper thread
will run __migrate_task().

kernel/sched/core.c:__migrate_task() {
    ...
    if (!is_cpu_allowed(p, dest_cpu))
        return rq;
    ...
}

Since the destination is non-preferred, won't is_cpu_allowed() reject it,
causing the stopper thread to silently abort the migration and break load
distribution?

While follow-up patches in the series restrict the busiest CPU to preferred
CPUs, they do not appear to prevent the destination from being non-preferred,
leaving this active load balancing path broken.

[Severity: High]
Can this rejection introduce a race condition with CPU hotplug that breaks
a task's user-configured affinity?

In select_fallback_rq() in kernel/sched/core.c, the loop might skip an
active, non-preferred CPU because task_can_migrate_to_preferred() indicates
another preferred CPU is available in the affinity mask. If a concurrent
CPU hotplug operation removes that preferred CPU from the active mask before
the loop reaches it, the loop will skip it too:

kernel/sched/core.c:select_fallback_rq() {
    ...
    for_each_cpu(dest_cpu, p->cpus_ptr) {
        if (!is_cpu_allowed(p, dest_cpu))
            continue;
    ...
}

Could the loop then terminate without finding any allowed CPU, permanently
forcing the task outside of its allowed affinity?

>  		return cpu_active(cpu);
> +	}

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260928053728.797539-1-sshegde@linux.ibm.com?part=6

  reply	other threads:[~2026-09-28  6:00 UTC|newest]

Thread overview: 32+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-28  5:37 [PATCH v14 00/13] sched, steal_governor: Introduce preferred CPUs and steal-driven vCPU backoff Shrikanth Hegde
2026-09-28  5:37 ` [PATCH v14 01/13] sched/cputime: Add kcpustat_field_total helper Shrikanth Hegde
2026-09-28  5:54   ` sashiko-bot
2026-09-28  5:37 ` [PATCH v14 02/13] cpumask: Introduce cpumask_intersects_and Shrikanth Hegde
2026-09-28  5:44   ` sashiko-bot
2026-09-28  5:37 ` [PATCH v14 03/13] sched/docs: Document cpu_preferred_mask and Preferred CPU concept Shrikanth Hegde
2026-09-28  5:42   ` sashiko-bot
2026-09-28  5:37 ` [PATCH v14 04/13] cpumask: Introduce cpu_preferred_mask Shrikanth Hegde
2026-09-28  5:46   ` sashiko-bot
2026-09-28  5:37 ` [PATCH v14 05/13] sysfs: Add preferred CPU file Shrikanth Hegde
2026-09-28  5:47   ` sashiko-bot
2026-09-28  5:37 ` [PATCH v14 06/13] sched/core: Try to use a preferred CPU in is_cpu_allowed Shrikanth Hegde
2026-09-28  6:00   ` sashiko-bot [this message]
2026-09-28  6:48     ` Shrikanth Hegde
2026-09-28  5:37 ` [PATCH v14 07/13] sched/fair: Load balance only among preferred CPUs Shrikanth Hegde
2026-09-28  5:55   ` sashiko-bot
2026-09-28  5:37 ` [PATCH v14 08/13] sched/core: Push current task from non preferred CPU Shrikanth Hegde
2026-09-28  5:56   ` sashiko-bot
2026-09-28  5:37 ` [PATCH v14 09/13] sched/debug: Add migration stats due to non preferred CPUs Shrikanth Hegde
2026-09-28  5:48   ` sashiko-bot
2026-09-29 12:18   ` Nathan Chancellor
2026-09-29 12:43     ` Shrikanth Hegde
2026-09-29 14:57       ` Shrikanth Hegde
2026-09-28  5:37 ` [PATCH v14 10/13] virt: Introduce steal governor driver Shrikanth Hegde
2026-09-28  5:47   ` sashiko-bot
2026-09-28  5:37 ` [PATCH v14 11/13] virt/steal_governor: Add control knobs for handling steal values Shrikanth Hegde
2026-09-28  5:46   ` sashiko-bot
2026-09-28  5:37 ` [PATCH v14 12/13] virt/steal_governor: Implement steal_governor policy loop Shrikanth Hegde
2026-09-28  5:51   ` sashiko-bot
2026-09-28  6:52     ` Shrikanth Hegde
2026-09-28  5:37 ` [PATCH v14 13/13] virt/steal_governor: Enable the driver Shrikanth Hegde
2026-09-28  5:48   ` sashiko-bot

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=20260928060002.C0D711F000FF@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=eperezma@redhat.com \
    --cc=mst@redhat.com \
    --cc=sashiko-reviews@lists.linux.dev \
    --cc=sshegde@linux.ibm.com \
    --cc=virtualization@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