[PATCH v4 11/26] sched/deadline: Reject SCHED_DEADLINE on exited tasks

From: Mathieu Desnoyers

Date: Fri Nov 06 2026 - 20:50:24 EST


From: Juri Lelli <juri.lelli@xxxxxxxxxx>

sched_setattr(SCHED_DEADLINE) on a zombie task succeeds and charges
total_bw via sched_dl_overflow(), but the task has already done its
final schedule() and will never run again. Nothing releases the reserved
bandwidth. Repeating this fills total_bw to the admission cap, after
which sched_setattr(SCHED_DEADLINE) and CPU offline fail with -EBUSY.

Reject sched_setattr(SCHED_DEADLINE) on exited tasks with -ESRCH.

A task of the class that exited, switched to another policy, runs
switched_from_dl(), which decrements the count of deadline tasks of its
cpuset that cgroup_task_dead() decremented already: at 0 with a deadline
task left in it, the cpuset is skipped by the next rebuild of the root
domains' accounting, and that task's bandwidth with it. Reject that as
well. The deadline_bw_test selftest added later in this series has the
case, death_zombie_switched: on v7.4-rc1 the switch is accepted, and
the one-CPU partition root the zombie ran in admits 9 tasks of 10% after
a rebuild, with a task of 30% still in it, where 6 are due.

Fixes: 332ac17ef5bf ("sched/deadline: Add bandwidth management for SCHED_DEADLINE tasks")
Reported-by: Weiheng Qiu <weihengqiuu@xxxxxxxxx>
Closes: https://lore.kernel.org/all/3f6e6c87-645b-45fd-8fc6-8da5bc5b82d8@xxxxxxxxx/
Link: https://lore.kernel.org/all/20261103-b4-sched-dl-bw-fixes-v1-4-dd761fe005b4@xxxxxxxxxx/
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Juri Lelli <juri.lelli@xxxxxxxxxx>
[mathieu: reject a task of the class leaving it too, found by the
Sashiko AI review of the patch]
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@xxxxxxxxxxxx>
---
kernel/sched/syscalls.c | 13 +++++++++++++
1 file changed, 13 insertions(+)

diff --git a/kernel/sched/syscalls.c b/kernel/sched/syscalls.c
index 89c185f7d498..12830e4f8842 100644
--- a/kernel/sched/syscalls.c
+++ b/kernel/sched/syscalls.c
@@ -584,6 +584,19 @@ int __sched_setscheduler(struct task_struct *p,
if (retval)
goto unlock;

+ /*
+ * Reject SCHED_DEADLINE on exited tasks. A zombie will never be
+ * scheduled again, so sched_dl_overflow() would charge total_bw
+ * that nothing will ever release. And reject a change of policy of
+ * one in the class: cgroup_task_dead() took it off the count of
+ * deadline tasks of its cpuset, which switched_from_dl() would
+ * decrement a second time.
+ */
+ if ((dl_policy(policy) || dl_task(p)) && p->exit_state) {
+ retval = -ESRCH;
+ goto unlock;
+ }
+
/*
* If not changing anything there's no need to proceed further,
* but store a possible modification of reset_on_fork.
--
2.47.3