Re: [PATCH v2 15/21] sched/deadline: Record the root domain holding a task's bandwidth
From: Mathieu Desnoyers
Date: Thu Nov 05 2026 - 14:16:11 EST
On 2026-11-04 18:31, sashiko-bot@xxxxxxxxxx wrote:
[...]
[Severity: High]
Can root domain bandwidth accounting be corrupted during a rebuild when a
departed task is boosted into dl_sched_class via priority inheritance before
its 0-lag time expires?
When a SCHED_DEADLINE task leaves the deadline policy before its 0-lag time,
switched_from_dl() arms inactive_timer and calls dl_task_depart(p) to link
p->dl.dl_departed_node onto dl_departed_list with p->dl.dl_bw_cpu recording
its root domain CPU. If p is then PI-boosted via rt_mutex_setprio() ->
switched_to_dl(), dl_task_undepart(p) unlinks p->dl.dl_departed_node while
preserving p->dl.dl_bw_cpu.
If dl_rebuild_rd_accounting() runs while p is PI-boosted,
dl_add_task_root_domain(p) sees list_empty(&p->dl.dl_departed_node) == true:
1. If p was moved to another cpuset partition while in SCHED_NORMAL (where no
deadline admission check ran because !dl_task(p)), dl_add_task_root_domain(p)
ignores p->dl.dl_bw_cpu, adds p->dl.dl_bw to the new cpuset's root domain via
dl_get_task_effective_cpus(p), and overwrites p->dl.dl_bw_cpu with cpu. Or,
if an earlier rebuild had already dropped p's departing bandwidth, this path
resurrects p->dl.dl_bw into p's effective cpuset.
2. Because rt_mutex_setprio() only holds p->pi_lock and rq->__lock (not
cpuset_mutex or dl_accounting_mutex), p can be PI-boosted when
dl_clear_root_domains() runs (so it is not on dl_departed_list and is not
restored there) and then deboost via rt_mutex_setprio() -> switched_from_dl()
before the task walk reaches p. switched_from_dl() puts p back onto
dl_departed_list after dl_clear_root_domains() has already finished, and
dl_add_task_root_domain(p) skips p because !dl_task(p) is now true, dropping
p's active 0-lag bandwidth completely.
[ Repeating answer to PATCH v2 09/21, which is also relevant here. ]
A departed task boosted into the class before its 0-lag time is counted
once, wherever a rebuild runs: the walk finds it in the class and counts
it in its cpuset's root domain, the record is updated, and the release at
the deboost reads the record. Where the deboost races the walk, the
departing bandwidth is dropped for the remaining lag, as it is for a
departed task whose recorded CPU went inactive; the generation keeps the
release out, so nothing underflows.
A rebuild that finds a CPU for a task an earlier one dropped counts it again,
which is the intent: the bandwidth of a departed task is held until its 0-lag
time.
3. For a regular non-deadline task with p->dl.dl_bw == 0 that is PI-boosted
during a rebuild, dl_add_task_root_domain(p) unconditionally sets
p->dl.dl_bw_cpu = cpu, leaving a non-negative dl_bw_cpu on a task with zero
bandwidth after it deboosts.
Should a departed task stay on dl_departed_list across PI boost/deboost until
its bandwidth is actually released, and should dl_add_task_root_domain(p) skip
tasks with p->dl.dl_bw == 0?
Part 3 is fixed in v3: the walk skips a task with no bandwidth of its own, so a
boosted task gets no record. A departed task need not stay on the list across a
boost: the record stays, and the release at the deboost reads it.
[Severity: Medium]
Does updating a task's deadline parameters while it is asleep after moving to
a new cpuset partition still use the stale task_cpu(p) root domain in
__sched_setscheduler() and sched_dl_overflow()?
The EPERM is the baseline's affinity check of __sched_setscheduler(),
which compares the span of the runqueue the sleeping task is on with its
new mask; out of scope here. The uncounted path runs with admission
control off alone.
Thanks,
Mathieu
--
Mathieu Desnoyers
EfficiOS Inc.
https://www.efficios.com