mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Mathieu Desnoyers" <mathieu.desnoyers@efficios.com>
Cc: linux-rt-devel@lists.linux.dev, tj@kernel.org,
	hannes@cmpxchg.org, mkoutny@suse.com,
	linux-kernel@vger.kernel.org
Subject: Re: [PATCH v3 18/24] sched/deadline: Credit a rebuild to the CPU recorded with the task's bandwidth
Date: Thu, 05 Nov 2026 20:58:52 +0000	[thread overview]
Message-ID: <sashiko-outbox-200171@kernel.org> (raw)
In-Reply-To: <20261105193359.1450487-19-mathieu.desnoyers@efficios.com>

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] sched/deadline: stale HK_TYPE_DOMAIN mask used in dl_get_task_effective_cpus()
- [High] sched/deadline: dl_task_rebuild_cpu() drops cpu from dl_task_offline_migration()
--

commit 8fc0e93077a2156f71e1f02a2a295664e07d7e75
Author: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>

sched/deadline: Credit a rebuild to the CPU recorded with the task's bandwidth

This commit adds dl_task_rebuild_cpu() so that root domain bandwidth
rebuilds credit a deadline task's bandwidth to its previously recorded
CPU when active and allowed, falling back to an active housekeeping or
cpuset-allowed CPU, or skipping the task when no active CPU is available.

> diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c
> index a058e0c65eca4..bcf7f88b204ad 100644
> --- a/kernel/sched/deadline.c
> +++ b/kernel/sched/deadline.c
> @@ -3607,6 +3607,36 @@ static void dl_get_task_effective_cpus(struct task_struct *p, struct cpumask *cp
>  	cpuset_cpus_allowed_locked(p, cpus);
>  }
>  
> +/*
> + * A CPU of the root domain that a rebuild of the accounting counts @p's
> + * bandwidth in. The one recorded with it, where it is active and the
> + * cpuset of @p allows it: that of the root domain that admitted the
> + * bandwidth, or that the last move put it in, which the cpuset alone does
> + * not tell where it holds CPUs of two root domains, housekeeping ones
> + * beside the ones isolcpus="domain" leaves to the default root domain. The
> + * record answers as well for a task whose own CPUs went offline, moved to
> + * an active one by dl_task_offline_migration(). Else the first active CPU
> + * the cpuset allows, a housekeeping one where it has any; and nr_cpu_ids
> + * where it allows none, which the isolated CPUs allow, no deadline task
> + * of theirs keeping the last of them online.
> + */
> +static unsigned int dl_task_rebuild_cpu(struct task_struct *p)
> +{
> +	struct cpumask *msk = this_cpu_cpumask_var_ptr(local_cpu_mask_dl);
> +	int recorded = p->dl.dl_bw_cpu;
> +	unsigned int cpu;
> +
> +	dl_get_task_effective_cpus(p, msk);
> +	cpumask_and(msk, msk, cpu_active_mask);
> +	if (recorded >= 0 && cpu_active(recorded) &&
> +	    (cpumask_test_cpu(recorded, msk) || cpumask_empty(msk)))
> +		return recorded;

[Severity: High]
As reported by Sashiko on v2 [1], does calling dl_get_task_effective_cpus()
here still observe the lagging HK_TYPE_DOMAIN mask during cpuset partition
transitions?

In kernel/sched/deadline.c, dl_get_task_effective_cpus() checks
housekeeping_cpumask(HK_TYPE_DOMAIN):

    hk_msk = housekeeping_cpumask(HK_TYPE_DOMAIN);
    if (housekeeping_enabled(HK_TYPE_DOMAIN)) {
        if (!cpumask_intersects(p->cpus_ptr, hk_msk)) {
            cpumask_andnot(cpus, cpu_active_mask, hk_msk);
            return;
        }
    }

Because cpuset_update_sd_hk_unlock() and cpuset_handle_hotplug() invoke
rebuild_sched_domains_locked() -> dl_rebuild_rd_accounting() before calling
housekeeping_update(), HK_TYPE_DOMAIN still reflects the pre-transition
isolated partitions and excludes all CPUs in any PRS_ISOLATED partition.

For example, if an isolated partition on CPUs 2-3 containing a deadline task
p admitted on CPU 2 (p->dl.dl_bw_cpu == 2) is shrunk to CPU 3, CPU 2 returns
to top_cpuset's root domain while cpuset_update_tasks_cpumask() updates
p->cpus_ptr to {3} without SCA_DL_BW_RESERVED. During the rebuild,
HK_TYPE_DOMAIN still excludes both CPU 2 and CPU 3, so
dl_get_task_effective_cpus() sets msk to {2, 3}. In dl_task_rebuild_cpu(),
cpumask_test_cpu(recorded, msk) then succeeds for CPU 2 (and the fallback
cpumask_first_and(msk, housekeeping_cpumask(HK_TYPE_DOMAIN_BOOT)) would also
pick CPU 2), crediting p's bandwidth to top_cpuset's root domain instead of
def_root_domain.

Similarly, if another CPU (such as CPU 1) is isolated by isolcpus=domain,1
or in another isolated partition while an isolated partition on CPU 2
transitions from PRS_ISOLATED to PRS_ROOT or PRS_MEMBER, HK_TYPE_DOMAIN
still excludes {1, 2} during the rebuild, so dl_get_task_effective_cpus()
sets msk to {1, 2} rather than the cpuset's allowed CPUs {2}. Conversely,
because HK_TYPE_DOMAIN is built from cpu_possible_mask, if a task running on
boot-isolated CPUs in def_root_domain has offline housekeeping CPUs in
p->cpus_ptr, cpumask_intersects(p->cpus_ptr, hk_msk) evaluates to true and
falls through to cpuset_cpus_allowed_locked(), causing dl_task_rebuild_cpu()
to prefer an active housekeeping CPU over remaining active isolated CPUs in
def_root_domain when the recorded CPU goes offline.

> +	cpu = cpumask_first_and(msk, housekeeping_cpumask(HK_TYPE_DOMAIN_BOOT));
> +	if (cpu < nr_cpu_ids)
> +		return cpu;
> +	return cpumask_first(msk);
> +}
> +
>  /* The caller should hold cpuset_mutex */
>  void dl_add_task_root_domain(struct task_struct *p)
>  {
> @@ -3614,7 +3644,6 @@ void dl_add_task_root_domain(struct task_struct *p)
>  	struct rq *rq;
>  	struct dl_bw *dl_b;
>  	unsigned int cpu;
> -	struct cpumask *msk;
>  
>  	raw_spin_lock_irqsave(&p->pi_lock, rf.flags);
>  	/*
> @@ -3626,10 +3655,16 @@ void dl_add_task_root_domain(struct task_struct *p)
>  		return;
>  	}
>  
> -	msk = this_cpu_cpumask_var_ptr(local_cpu_mask_dl);
> -	dl_get_task_effective_cpus(p, msk);
> -	cpu = cpumask_first_and(cpu_active_mask, msk);
> -	BUG_ON(cpu >= nr_cpu_ids);
> +	cpu = dl_task_rebuild_cpu(p);
> +	if (cpu >= nr_cpu_ids) {
> +		/*
> +		 * No active CPU to count this task's bandwidth: leave it out
> +		 * of this rebuild, where dl_bw_gen keeps its release out as
> +		 * well, until one has a CPU for it.
> +		 */
> +		raw_spin_unlock_irqrestore(&p->pi_lock, rf.flags);
> +		return;
> +	}

[Severity: High]
As reported by Sashiko on v2 [2], can a throttled deadline task migrated by
dl_task_offline_migration() still have its bandwidth credited to the wrong
root domain or left unaccounted?

When all CPUs in p->cpus_ptr are offline, dl_task_offline_migration() sees
cpumask_any_and(cpu_active_mask, p->cpus_ptr) >= nr_cpu_ids and falls back to
cpumask_any(cpu_active_mask), moving the task and p->dl.dl_bw_cpu to an
active CPU while p->cpus_ptr still contains only the offline CPUs.

In dl_task_rebuild_cpu(), the check preserving recorded when the task's own
CPUs are offline tests cpumask_empty(msk), where msk is the result of
dl_get_task_effective_cpus(p, msk) & cpu_active_mask rather than
p->cpus_ptr & cpu_active_mask. If other CPUs in msk remain active outside
p->cpus_ptr (for instance, with isolcpus=domain,1,2 when p is affined to
CPU 1 and CPU 1 goes offline while CPU 2 stays online, or when p is pinned
to one CPU of a multi-CPU cpuset with admission control disabled and moved to
another partition's CPU), msk is non-empty ({2}) and does not contain the
fallback CPU recorded by dl_task_offline_migration() (such as CPU 0).
dl_task_rebuild_cpu() then rejects recorded and credits p's bandwidth to
CPU 2's root domain while p runs on CPU 0.

Additionally, during CPU deactivation in sched_cpu_deactivate(),
cpuset_cpu_inactive() runs dl_rebuild_rd_accounting() immediately after
sched_set_rq_offline(), before a throttled task's hrtimer fires
dl_task_timer() -> dl_task_offline_migration(). If the deactivated CPU was
the task's last active CPU in msk, dl_task_rebuild_cpu() returns nr_cpu_ids
and dl_add_task_root_domain() returns early without updating
p->dl.dl_bw_gen. When dl_task_timer() subsequently fires and calls
dl_task_offline_migration():

    scoped_guard (raw_spinlock, &dl_departed_lock) {
        if (p->dl.dl_bw_gen == dl_bw_gen) {
            ...
            __dl_add(dl_b, p->dl.dl_bw,
                     cpumask_weight(later_rq->rd->span));
            raw_spin_unlock(&dl_b->lock);
        }
        p->dl.dl_bw_cpu = later_rq->cpu;
    }

Because p->dl.dl_bw_gen != dl_bw_gen, doesn't dl_task_offline_migration()
skip adding p->dl.dl_bw to later_rq->rd->dl_bw, leaving the migrated task's
bandwidth unaccounted until another root domain rebuild occurs?

[1] https://lore.kernel.org/r/sashiko-outbox-198343@kernel.org
[2] https://lore.kernel.org/r/sashiko-outbox-198343@kernel.org

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261105193359.1450487-1-mathieu.desnoyers@efficios.com?part=18

  reply	other threads:[~2026-11-05 20:58 UTC|newest]

Thread overview: 38+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-05 19:33 [PATCH v3 00/24] sched/deadline: bandwidth accounting fixes and selftests Mathieu Desnoyers
2026-11-05 19:33 ` [PATCH v3 01/24] sched: Fix cpuset_mutex double unlock in __sched_setscheduler() Mathieu Desnoyers
2026-11-05 19:51   ` Kayra Cizmeci
2026-11-05 19:54     ` Mathieu Desnoyers
2026-11-05 19:59       ` Mathieu Desnoyers
2026-11-05 19:33 ` [PATCH v3 02/24] sched: Refuse SCHED_FLAG_KEEP_PARAMS that would change the policy or the class Mathieu Desnoyers
2026-11-05 19:33 ` [PATCH v3 03/24] sched/deadline: Do not admit bandwidth for parameters that are kept Mathieu Desnoyers
2026-11-05 19:33 ` [PATCH v3 04/24] sched/deadline: Do not divide by zero active CPUs of a root domain Mathieu Desnoyers
2026-11-05 19:59   ` sashiko-bot
2026-11-05 19:33 ` [PATCH v3 05/24] sched: Take cpuset_mutex for a deadline policy change only with pi Mathieu Desnoyers
2026-11-05 19:33 ` [PATCH v3 06/24] sched/deadline: Do not lose a throttled task switched out and back Mathieu Desnoyers
2026-11-05 19:33 ` [PATCH v3 07/24] sched/deadline: Reset the deadline and the runtime with the parameters Mathieu Desnoyers
2026-11-05 19:33 ` [PATCH v3 08/24] sched/deadline: Release the bandwidth of a task that leaves the class asleep Mathieu Desnoyers
2026-11-05 20:10   ` sashiko-bot
2026-11-05 19:33 ` [PATCH v3 09/24] sched/deadline: Reject SCHED_DEADLINE on exited tasks Mathieu Desnoyers
2026-11-05 19:33 ` [PATCH v3 10/24] sched/deadline: Keep departing bandwidth across a root domain rebuild Mathieu Desnoyers
2026-11-05 19:33 ` [PATCH v3 11/24] sched/deadline: Do not take a waking task's bandwidth off a runqueue it left Mathieu Desnoyers
2026-11-05 20:35   ` sashiko-bot
2026-11-05 19:33 ` [PATCH v3 12/24] sched/deadline: Rebuild the root domains' accounting without cpusets too Mathieu Desnoyers
2026-11-05 19:33 ` [PATCH v3 13/24] sched/deadline: Leave a dying task out of a rebuild of the accounting Mathieu Desnoyers
2026-11-05 19:33 ` [PATCH v3 14/24] sched/deadline: Record the root domain holding a task's bandwidth Mathieu Desnoyers
2026-11-05 20:50   ` sashiko-bot
2026-11-05 19:33 ` [PATCH v3 15/24] sched/deadline: Move a task's bandwidth only where room was made Mathieu Desnoyers
2026-11-05 19:33 ` [PATCH v3 16/24] cgroup/cpuset: Wait for an attach before rebuilding the sched domains Mathieu Desnoyers
2026-11-05 20:36   ` sashiko-bot
2026-11-05 19:33 ` [PATCH v3 17/24] cgroup/cpuset: Give back the bandwidth an attach did not move Mathieu Desnoyers
2026-11-05 19:33 ` [PATCH v3 18/24] sched/deadline: Credit a rebuild to the CPU recorded with the task's bandwidth Mathieu Desnoyers
2026-11-05 20:58   ` sashiko-bot [this message]
2026-11-05 19:33 ` [PATCH v3 19/24] sched/deadline: Cancel the replenishment timer with the parameters Mathieu Desnoyers
2026-11-05 21:05   ` sashiko-bot
2026-11-05 19:33 ` [PATCH v3 20/24] sched/deadline: Count the bandwidth a boosted task is given Mathieu Desnoyers
2026-11-05 21:13   ` sashiko-bot
2026-11-05 19:33 ` [PATCH v3 21/24] sched/debug: Show the deadline bandwidth of each runqueue Mathieu Desnoyers
2026-11-05 19:33 ` [PATCH v3 22/24] selftests/sched: Add a test of SCHED_DEADLINE policy round trips Mathieu Desnoyers
2026-11-05 19:33 ` [PATCH v3 23/24] selftests/sched: Test SCHED_DEADLINE bandwidth across a root domain rebuild Mathieu Desnoyers
2026-11-05 19:33 ` [PATCH v3 24/24] selftests/sched: Add a test of SCHED_DEADLINE bandwidth accounting Mathieu Desnoyers
2026-11-05 21:17   ` sashiko-bot
2026-11-05 21:20 ` [PATCH v3 00/24] sched/deadline: bandwidth accounting fixes and selftests Mathieu Desnoyers

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-200171@kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=hannes@cmpxchg.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-rt-devel@lists.linux.dev \
    --cc=mathieu.desnoyers@efficios.com \
    --cc=mkoutny@suse.com \
    --cc=sashiko-reviews@lists.linux.dev \
    --cc=tj@kernel.org \
    /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®