From: Tejun Heo <tj@kernel.org>
To: Juri Lelli <juri.lelli@redhat.com>,
Peter Zijlstra <peterz@infradead.org>
Cc: Ingo Molnar <mingo@redhat.com>,
Vincent Guittot <vincent.guittot@linaro.org>,
Dietmar Eggemann <dietmar.eggemann@arm.com>,
Valentin Schneider <vschneid@redhat.com>,
K Prateek Nayak <kprateek.nayak@amd.com>,
Luca Abeni <luca.abeni@santannapisa.it>,
Andrea Righi <arighi@nvidia.com>,
sched-ext@lists.linux.dev, linux-kernel@vger.kernel.org
Subject: sched/deadline: total_bw leak when a task leaves SCHED_DEADLINE while not queued
Date: Thu, 29 Oct 2026 11:55:10 -1000 [thread overview]
Message-ID: <2b5fb3f22bca6aa383be8f4781923392@kernel.org> (raw)
Hello,
A SCHED_DEADLINE task that is switched to another policy while it isn't
queued (sleeping, or stopped with SIGSTOP) leaves its bandwidth in the root
domain's total_bw. The bandwidth stays after the task exits. The leak
happens as follows.
1. sched_dl_overflow() doesn't subtract the bandwidth of a task leaving
DEADLINE and leaves that to switched_from_dl().
2. switched_from_dl() calls task_non_contending() only for a queued task.
task_non_contending() releases the bandwidth right away if the 0-lag time
has passed and otherwise arms the inactive timer, and
inactive_task_timer() releases it once the task is no longer dl_task().
3. For a task that isn't queued, the bandwidth is released only if its
inactive timer is still pending from its dequeue. No timer is pending if
the task never ran as DEADLINE, or if it already fired while the task
slept. In the latter case the task was still DEADLINE when the timer
fired, so it only dropped running_bw. Either way, nothing releases the
bandwidth.
Repeating it fills total_bw up to the admission cap. After that,
sched_setattr(SCHED_DEADLINE) and CPU offline fail with -EBUSY, and so does
enabling a sched_ext scheduler, because attaching the ext dl_server
bandwidth fails:
sched_ext: failed to attach ext_server on CPU 0 (-16)
sched_ext: simple: scx_root_enable() failed (-16)
The reproducer below needs root and debugfs, and assumes x86-64 for the
syscall number 314.
import ctypes, os, signal, time
libc = ctypes.CDLL(None, use_errno=True)
class SchedAttr(ctypes.Structure):
_fields_ = [("size", ctypes.c_uint32), ("policy", ctypes.c_uint32),
("flags", ctypes.c_uint64), ("nice", ctypes.c_int32),
("prio", ctypes.c_uint32), ("runtime", ctypes.c_uint64),
("deadline", ctypes.c_uint64), ("period", ctypes.c_uint64)]
def setattr_(pid, policy, runtime=0, period=0):
a = SchedAttr(ctypes.sizeof(SchedAttr), policy, 0, 0, 0, runtime, period, period)
if libc.syscall(314, pid, ctypes.byref(a), 0): # sched_setattr
raise OSError(ctypes.get_errno(), "sched_setattr")
def total_bw():
s = open("/sys/kernel/debug/sched/debug").read().split("dl_rq[0]:")[1]
return int(s.split("dl_bw->total_bw")[1].split(":")[1].split()[0])
def trial(name, body, stop=False):
pid = os.fork()
if pid == 0:
if body == "spin":
while True:
pass
while True:
time.sleep(3600)
time.sleep(0.05)
bw0 = total_bw()
setattr_(pid, 6, runtime=2_000_000, period=10_000_000) # DEADLINE 2ms/10ms
if stop:
os.kill(pid, signal.SIGSTOP)
time.sleep(0.02)
setattr_(pid, 0) # back to OTHER
os.kill(pid, signal.SIGKILL)
os.waitpid(pid, 0)
time.sleep(0.05)
print(f"{name:24s} leaked total_bw {total_bw() - bw0:7d} (0.2 CPU = 209715)")
trial("sleeping dl>other", "sleep")
trial("stopped dl>other", "spin", stop=True)
trial("running dl>other", "spin") # control
On mainline 4dd16e31135e it prints:
sleeping dl>other leaked total_bw 209715 (0.2 CPU = 209715)
stopped dl>other leaked total_bw 209715 (0.2 CPU = 209715)
running dl>other leaked total_bw 0 (0.2 CPU = 209715)
Thanks.
--
tejun
next reply other threads:[~2026-10-29 21:55 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-29 21:55 Tejun Heo [this message]
2026-10-30 9:22 ` Juri Lelli
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=2b5fb3f22bca6aa383be8f4781923392@kernel.org \
--to=tj@kernel.org \
--cc=arighi@nvidia.com \
--cc=dietmar.eggemann@arm.com \
--cc=juri.lelli@redhat.com \
--cc=kprateek.nayak@amd.com \
--cc=linux-kernel@vger.kernel.org \
--cc=luca.abeni@santannapisa.it \
--cc=mingo@redhat.com \
--cc=peterz@infradead.org \
--cc=sched-ext@lists.linux.dev \
--cc=vincent.guittot@linaro.org \
--cc=vschneid@redhat.com \
/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®