From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
To: linux-kernel@vger.kernel.org, cgroups@vger.kernel.org,
rcu@vger.kernel.org, linux-doc@vger.kernel.org
Cc: "Sebastian Andrzej Siewior" <bigeasy@linutronix.de>,
"Jonathan Corbet" <corbet@lwn.net>,
"Shuah Khan" <skhan@linuxfoundation.org>,
"Randy Dunlap" <rdunlap@infradead.org>,
"Ingo Molnar" <mingo@redhat.com>,
"Peter Zijlstra" <peterz@infradead.org>,
"Juri Lelli" <juri.lelli@redhat.com>,
"Vincent Guittot" <vincent.guittot@linaro.org>,
"Dietmar Eggemann" <dietmar.eggemann@arm.com>,
"Steven Rostedt" <rostedt@goodmis.org>,
"Ben Segall" <bsegall@google.com>, "Mel Gorman" <mgorman@suse.de>,
"Valentin Schneider" <vschneid@redhat.com>,
"K Prateek Nayak" <kprateek.nayak@amd.com>,
"luca abeni" <luca.abeni@santannapisa.it>,
"Yuri Andriaccio" <yurand2000@gmail.com>,
"Yuri Andriaccio" <yuri.andriaccio@santannapisa.it>,
"Paul E. McKenney" <paulmck@kernel.org>,
"Frederic Weisbecker" <frederic@kernel.org>,
"Neeraj Upadhyay" <neeraj.upadhyay@kernel.org>,
"Joel Fernandes" <joelagnelf@nvidia.com>,
"Josh Triplett" <josh@joshtriplett.org>,
"Boqun Feng" <boqun@kernel.org>,
"Uladzislau Rezki" <urezki@gmail.com>,
"Mathieu Desnoyers" <mathieu.desnoyers@efficios.com>,
"Lai Jiangshan" <jiangshanlai@gmail.com>,
Zqiang <qiang.zhang@linux.dev>,
"Davidlohr Bueso" <dave@stgolabs.net>,
"Tejun Heo" <tj@kernel.org>,
"Johannes Weiner" <hannes@cmpxchg.org>,
"Michal Koutný" <mkoutny@suse.com>,
"Qais Yousef" <qyousef@layalina.io>,
"John Ogness" <john.ogness@linutronix.de>
Subject: [PATCH v3 5/8] sched: Move DL's admission control to sysfs
Date: Fri, 13 Nov 2026 11:50:26 +0100 [thread overview]
Message-ID: <20261113-sched_dl-v3-5-a76ffa1cdeee@linutronix.de> (raw)
In-Reply-To: <20261113-sched_dl-v3-0-a76ffa1cdeee@linutronix.de>
SCHED_DL uses the sysctl sched_rt_{period|runtime}_us to configure its
admission control. It is used to verify that it does not allocate more
time gobally to SCHED_DL tasks than it can theoretically handle.
This sysctl used to control RT throttling. With the introduction of the
DL server this knob controls RT throttling within a RT-cgroup if
CONFIG_RT_GROUP_SCHED is enabled. In this case the knob is also stuck
and can not be changed. So it can not be used for SCHED_DL control at
all. Unless to disable it by writing -1.
Split the DL bits into its knob at sysfs' location. Once the DL logic
is out, sched_domains_mutex.*() and rebuild_sched_domains() can be
removed from sched_rt_handler().
Move SCHED_DL usage of this sysctl to /sys/kernel/sched/ as
dl_runtime_us + dl_period_us. Replace global_rt_period()/
global_rt_runtime() with sysfs_dl_period/ sysfs_dl_runtime. Store the
new attribues in ns. Move global_rt_period()/ global_rt_runtime() to
CONFIG_RT_GROUP_SCHED.
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
---
Documentation/arch/arm64/asymmetric-32bit.rst | 2 +-
Documentation/scheduler/sched-deadline.rst | 15 +--
kernel/sched/deadline.c | 165 ++++++++++++++++++++++++--
kernel/sched/rt.c | 25 +---
kernel/sched/sched.h | 31 +++--
5 files changed, 178 insertions(+), 60 deletions(-)
diff --git a/Documentation/arch/arm64/asymmetric-32bit.rst b/Documentation/arch/arm64/asymmetric-32bit.rst
index fc0c350c5e001..375958f8971e5 100644
--- a/Documentation/arch/arm64/asymmetric-32bit.rst
+++ b/Documentation/arch/arm64/asymmetric-32bit.rst
@@ -105,7 +105,7 @@ affinity for the task is updated and any saved mask from a prior
Explicit admission of a 32-bit deadline task to the default root domain
(e.g. by calling ``sched_setattr(2)``) is rejected on an asymmetric
32-bit system unless admission control is disabled by writing -1 to
-``/proc/sys/kernel/sched_rt_runtime_us``.
+``/sys/kernel/sched/dl_runtime_us``.
``execve(2)`` of a 32-bit program from a 64-bit deadline task will
return ``-ENOEXEC`` if the root domain for the task contains any
diff --git a/Documentation/scheduler/sched-deadline.rst b/Documentation/scheduler/sched-deadline.rst
index 9019b66f6a5ba..23ea88b2ed7dc 100644
--- a/Documentation/scheduler/sched-deadline.rst
+++ b/Documentation/scheduler/sched-deadline.rst
@@ -590,24 +590,19 @@ Deadline Task Scheduling
4.1 System wide settings
------------------------
- The system wide settings are configured under the /proc virtual file system.
+ The system wide settings are configured under /sys/kernel/sched.
- For now the -rt knobs are used for -deadline admission control and with
- CONFIG_RT_GROUP_SCHED the -deadline runtime is accounted against the (root)
- -rt runtime. With !CONFIG_RT_GROUP_SCHED the knob only serves for the -dl
- admission control. We realize that this isn't entirely desirable; however, it
- is better to have a small interface for now, and be able to change it easily
- later. The ideal situation (see 5.) is to run -rt tasks from a -deadline
- server; in which case the -rt bandwidth is a direct subset of dl_bw.
+ The ideal situation (see 5.) is to run -rt tasks from a -deadline server; in
+ which case the -rt bandwidth is a direct subset of dl_bw.
This means that, for a root_domain comprising M CPUs, -deadline tasks
can be created while the sum of their bandwidths stays below:
- M * (sched_rt_runtime_us / sched_rt_period_us)
+ M * (dl_runtime_us / dl_period_us)
It is also possible to disable this bandwidth management logic, and
be thus free of oversubscribing the system up to any arbitrary level.
- This is done by writing -1 in /proc/sys/kernel/sched_rt_runtime_us.
+ This is done by writing -1 in /sys/kernel/sched/dl_runtime_us.
4.2 Task interface
diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c
index a713ad9dd6208..839ae9a6acf63 100644
--- a/kernel/sched/deadline.c
+++ b/kernel/sched/deadline.c
@@ -23,6 +23,14 @@
#include "sched.h"
#include "pelt.h"
+/*
+ * Admission control for DL tasks. For a root_domain comprising M CPUs,
+ * -deadline tasks can be created while the sum of their bandwidths stays
+ * below: M * (dl_runtime / dl_period)
+ */
+static u64 sysfs_dl_period = 1000000 * NSEC_PER_USEC;
+u64 sysfs_dl_runtime = 1000000 * NSEC_PER_USEC;
+
/*
* Default limits for DL period; on the top end we guard against small util
* tasks still getting ridiculously long effective runtimes, on the bottom end we
@@ -509,10 +517,10 @@ static void init_dl_rq_bw_ratio(struct dl_rq *dl_rq);
void init_dl_bw(struct dl_bw *dl_b)
{
raw_spin_lock_init(&dl_b->lock);
- if (global_rt_runtime() == RUNTIME_INF)
+ if (sysfs_dl_runtime == RUNTIME_INF)
dl_b->bw = -1;
else
- dl_b->bw = to_ratio(global_rt_period(), global_rt_runtime());
+ dl_b->bw = to_ratio(sysfs_dl_period, sysfs_dl_runtime);
dl_b->total_bw = 0;
}
@@ -3718,10 +3726,8 @@ DEFINE_SCHED_CLASS(dl) = {
*/
u64 dl_cookie;
-int sched_dl_global_validate(void)
+static int sched_dl_global_validate(u64 runtime, u64 period)
{
- u64 runtime = global_rt_runtime();
- u64 period = global_rt_period();
u64 new_bw = to_ratio(period, runtime);
u64 cookie = ++dl_cookie;
struct dl_bw *dl_b;
@@ -3759,18 +3765,18 @@ int sched_dl_global_validate(void)
static void init_dl_rq_bw_ratio(struct dl_rq *dl_rq)
{
- if (global_rt_runtime() == RUNTIME_INF) {
+ if (sysfs_dl_runtime == RUNTIME_INF) {
dl_rq->bw_ratio = 1 << RATIO_SHIFT;
dl_rq->max_bw = dl_rq->extra_bw = 1 << BW_SHIFT;
} else {
- dl_rq->bw_ratio = to_ratio(global_rt_runtime(),
- global_rt_period()) >> (BW_SHIFT - RATIO_SHIFT);
+ dl_rq->bw_ratio = to_ratio(sysfs_dl_runtime,
+ sysfs_dl_period) >> (BW_SHIFT - RATIO_SHIFT);
dl_rq->max_bw = dl_rq->extra_bw =
- to_ratio(global_rt_period(), global_rt_runtime());
+ to_ratio(sysfs_dl_period, sysfs_dl_runtime);
}
}
-void sched_dl_do_global(void)
+static void sched_dl_do_global(void)
{
u64 new_bw = -1;
u64 cookie = ++dl_cookie;
@@ -3778,8 +3784,8 @@ void sched_dl_do_global(void)
int cpu;
unsigned long flags;
- if (global_rt_runtime() != RUNTIME_INF)
- new_bw = to_ratio(global_rt_period(), global_rt_runtime());
+ if (sysfs_dl_runtime != RUNTIME_INF)
+ new_bw = to_ratio(sysfs_dl_period, sysfs_dl_runtime);
for_each_possible_cpu(cpu)
init_dl_rq_bw_ratio(&cpu_rq(cpu)->dl);
@@ -4130,3 +4136,138 @@ void print_dl_stats(struct seq_file *m, int cpu)
{
print_dl_rq(m, cpu, &cpu_rq(cpu)->dl);
}
+
+#define SCHED_ATTR(_name) \
+ static struct kobj_attribute sched_attr_## _name = \
+ __ATTR(_name, 0644, sched_attr_##_name##_show, sched_attr_##_name##_store)
+
+static int sched_dl_try_boundary(int runtime, int period)
+{
+ static DEFINE_MUTEX(sched_dl_update_lock);
+ int ret;
+ u64 runtime_ns;
+ u64 period_ns;
+
+ guard(mutex)(&sched_dl_update_lock);
+ if (runtime) {
+ if (runtime < 0)
+ runtime_ns = RUNTIME_INF;
+ else
+ runtime_ns = (u64)runtime * NSEC_PER_USEC;
+ } else {
+ runtime_ns = sysfs_dl_runtime;
+ }
+
+ if (period)
+ period_ns = (u64)period * NSEC_PER_USEC;
+ else
+ period_ns = sysfs_dl_period;
+
+ if (runtime_ns != RUNTIME_INF) {
+ if (runtime_ns > period_ns || runtime_ns > MAX_BW)
+ return -EINVAL;
+ }
+
+ sched_domains_mutex_lock();
+ ret = sched_dl_global_validate(runtime_ns, period_ns);
+ if (ret) {
+ sched_domains_mutex_unlock();
+ return ret;
+ }
+
+ sysfs_dl_period = period_ns;
+ sysfs_dl_runtime = runtime_ns;
+
+ sched_dl_do_global();
+ sched_domains_mutex_unlock();
+ /*
+ * After changing maximum available bandwidth for DEADLINE, we need to
+ * recompute per root domain and per cpus variables accordingly.
+ */
+ rebuild_sched_domains();
+ return 0;
+}
+
+static ssize_t sched_attr_dl_runtime_us_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ u64 val = sysfs_dl_runtime;
+
+ if (val == RUNTIME_INF)
+ val = -1;
+ else
+ do_div(val, NSEC_PER_USEC);
+
+ return sysfs_emit(buf, "%lld\n", val);
+}
+
+static ssize_t sched_attr_dl_runtime_us_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf, size_t count)
+{
+ int val;
+ int ret;
+
+ ret = kstrtoint(buf, 0, &val);
+ if (ret)
+ return ret;
+
+ if (!(val == -1 || val > 0))
+ return -EINVAL;
+
+ ret = sched_dl_try_boundary(val, 0);
+ if (ret)
+ return ret;
+ return count;
+}
+SCHED_ATTR(dl_runtime_us);
+
+static ssize_t sched_attr_dl_period_us_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ u64 val = sysfs_dl_period;
+
+ do_div(val, NSEC_PER_USEC);
+ return sysfs_emit(buf, "%lld\n", val);
+}
+
+static ssize_t sched_attr_dl_period_us_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf, size_t count)
+{
+ int val;
+ int ret;
+
+ ret = kstrtoint(buf, 0, &val);
+ if (ret)
+ return ret;
+ if (val <= 0)
+ return -EINVAL;
+
+ ret = sched_dl_try_boundary(0, val);
+ if (ret)
+ return ret;
+ return count;
+}
+SCHED_ATTR(dl_period_us);
+
+static struct attribute *sched_global_attrs[] = {
+ &sched_attr_dl_runtime_us.attr,
+ &sched_attr_dl_period_us.attr,
+ NULL,
+};
+
+static const struct attribute_group sched_global_attrs_group = {
+ .attrs = sched_global_attrs,
+};
+
+static int __init sched_dl_init(void)
+{
+ struct kobject *sched_kobj;
+
+ sched_kobj = kobject_create_and_add("sched", kernel_kobj);
+ if (!sched_kobj)
+ return -ENOMEM;
+ return sysfs_create_group(sched_kobj, &sched_global_attrs_group);
+}
+late_initcall(sched_dl_init);
diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c
index cdeddd3fc9af2..1a6450f91d567 100644
--- a/kernel/sched/rt.c
+++ b/kernel/sched/rt.c
@@ -2871,7 +2871,6 @@ static int sched_rt_handler(const struct ctl_table *table, int write, void *buff
int ret;
mutex_lock(&mutex);
- sched_domains_mutex_lock();
old_period = sysctl_sched_rt_period;
old_runtime = sysctl_sched_rt_runtime;
@@ -2879,29 +2878,13 @@ static int sched_rt_handler(const struct ctl_table *table, int write, void *buff
if (!ret && write) {
ret = sched_rt_global_validate();
- if (ret)
- goto undo;
-
- ret = sched_dl_global_validate();
- if (ret)
- goto undo;
-
- sched_dl_do_global();
+ if (ret) {
+ sysctl_sched_rt_period = old_period;
+ sysctl_sched_rt_runtime = old_runtime;
+ }
}
- if (0) {
-undo:
- sysctl_sched_rt_period = old_period;
- sysctl_sched_rt_runtime = old_runtime;
- }
- sched_domains_mutex_unlock();
mutex_unlock(&mutex);
- /*
- * After changing maximum available bandwidth for DEADLINE, we need to
- * recompute per root domain and per cpus variables accordingly.
- */
- rebuild_sched_domains();
-
return ret;
}
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index a7964537bac75..00a3802d0ce04 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -109,6 +109,7 @@ extern long calc_load_fold_active(struct rq *this_rq, long adjust);
extern void call_trace_sched_update_nr_running(struct rq *rq, int count);
+extern u64 sysfs_dl_runtime;
extern int sysctl_sched_rt_period;
extern int sysctl_sched_rt_runtime;
extern int sched_rr_timeslice;
@@ -326,7 +327,7 @@ struct rt_bandwidth {
static inline int dl_bandwidth_enabled(void)
{
- return sysctl_sched_rt_runtime >= 0;
+ return sysfs_dl_runtime >= 0 && sysfs_dl_runtime != RUNTIME_INF;
}
/*
@@ -354,8 +355,6 @@ struct dl_bw {
};
extern void init_dl_bw(struct dl_bw *dl_b);
-extern int sched_dl_global_validate(void);
-extern void sched_dl_do_global(void);
extern int sched_dl_overflow(struct task_struct *p, int policy, const struct sched_attr *attr);
extern void __setparam_dl(struct task_struct *p, const struct sched_attr *attr);
extern void __getparam_dl(struct task_struct *p, struct sched_attr *attr, unsigned int flags);
@@ -599,6 +598,19 @@ static inline int rt_bandwidth_enabled(void)
{
return sysctl_sched_rt_runtime >= 0;
}
+
+static inline u64 global_rt_period(void)
+{
+ return (u64)sysctl_sched_rt_period * NSEC_PER_USEC;
+}
+
+static inline u64 global_rt_runtime(void)
+{
+ if (sysctl_sched_rt_runtime < 0)
+ return RUNTIME_INF;
+
+ return (u64)sysctl_sched_rt_runtime * NSEC_PER_USEC;
+}
#endif
extern struct task_group *sched_create_group(struct task_group *parent);
@@ -2505,19 +2517,6 @@ extern union sched_feat_key sched_feat_keys[__SCHED_FEAT_NR];
extern struct static_key_false sched_numa_balancing;
extern struct static_key_false sched_schedstats;
-static inline u64 global_rt_period(void)
-{
- return (u64)sysctl_sched_rt_period * NSEC_PER_USEC;
-}
-
-static inline u64 global_rt_runtime(void)
-{
- if (sysctl_sched_rt_runtime < 0)
- return RUNTIME_INF;
-
- return (u64)sysctl_sched_rt_runtime * NSEC_PER_USEC;
-}
-
/*
* Is p the current execution context?
*/
--
2.55.0
next prev parent reply other threads:[~2026-11-13 10:50 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-13 10:50 [PATCH v3 0/8] sched: RT throttling cleanup and a bit of documentation Sebastian Andrzej Siewior
2026-11-13 10:50 ` [PATCH v3 1/8] sched/deadline: Reject debugfs dl_server writes for not-active CPUs Sebastian Andrzej Siewior
2026-11-13 10:50 ` [PATCH v3 2/8] sched: Mark RT_GROUP_SCHED broken Sebastian Andrzej Siewior
2026-11-13 10:50 ` [PATCH v3 3/8] rcutorture: Don't try to disable to RT throttling Sebastian Andrzej Siewior
2026-11-13 10:50 ` [PATCH v3 4/8] sched: rcutorture: Allow to disable DL fair_server Sebastian Andrzej Siewior
2026-11-13 10:50 ` Sebastian Andrzej Siewior [this message]
2026-11-13 10:50 ` [PATCH v3 6/8] sched: Limit sysctl sched_rt_{period|runtime}_us to RT_GROUP_SCHED Sebastian Andrzej Siewior
2026-11-13 10:50 ` [PATCH v3 7/8] sched: Add sysfs files for the per-CPU fair_server knobs Sebastian Andrzej Siewior
2026-11-13 10:50 ` [PATCH v3 8/8] Documentation/sched: Add fairserver to sched-deadline Sebastian Andrzej Siewior
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=20261113-sched_dl-v3-5-a76ffa1cdeee@linutronix.de \
--to=bigeasy@linutronix.de \
--cc=boqun@kernel.org \
--cc=bsegall@google.com \
--cc=cgroups@vger.kernel.org \
--cc=corbet@lwn.net \
--cc=dave@stgolabs.net \
--cc=dietmar.eggemann@arm.com \
--cc=frederic@kernel.org \
--cc=hannes@cmpxchg.org \
--cc=jiangshanlai@gmail.com \
--cc=joelagnelf@nvidia.com \
--cc=john.ogness@linutronix.de \
--cc=josh@joshtriplett.org \
--cc=juri.lelli@redhat.com \
--cc=kprateek.nayak@amd.com \
--cc=linux-doc@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=luca.abeni@santannapisa.it \
--cc=mathieu.desnoyers@efficios.com \
--cc=mgorman@suse.de \
--cc=mingo@redhat.com \
--cc=mkoutny@suse.com \
--cc=neeraj.upadhyay@kernel.org \
--cc=paulmck@kernel.org \
--cc=peterz@infradead.org \
--cc=qiang.zhang@linux.dev \
--cc=qyousef@layalina.io \
--cc=rcu@vger.kernel.org \
--cc=rdunlap@infradead.org \
--cc=rostedt@goodmis.org \
--cc=skhan@linuxfoundation.org \
--cc=tj@kernel.org \
--cc=urezki@gmail.com \
--cc=vincent.guittot@linaro.org \
--cc=vschneid@redhat.com \
--cc=yurand2000@gmail.com \
--cc=yuri.andriaccio@santannapisa.it \
/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®