Add an interface for fair server setup on debugfs.
Each rq have three file under /sys/kernel/debug/sched/rq/CPU{ID}:
- fair_server_runtime: set runtime in ns
- fair_server_period: set period in ns
- fair_server_defer: on/off for the defer mechanism
Signed-off-by: Daniel Bristot de Oliveira <bristot@kernel.org>
---
kernel/sched/debug.c | 177 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 177 insertions(+)
diff --git a/kernel/sched/debug.c b/kernel/sched/debug.c
index 4c3d0d9f3db6..dad7d5d073ef 100644
--- a/kernel/sched/debug.c
+++ b/kernel/sched/debug.c
@@ -333,8 +333,183 @@ static const struct file_operations sched_debug_fops = {
.release = seq_release,
};
+static ssize_t
+sched_fair_server_runtime_write(struct file *filp, const char __user *ubuf,
+ size_t cnt, loff_t *ppos)
+{
+ long cpu = (long) ((struct seq_file *) filp->private_data)->private;
+ struct rq *rq = cpu_rq(cpu);
+ unsigned long flags;
+ u64 runtime;
+ int err;
+
+ err = kstrtoull_from_user(ubuf, cnt, 10, &runtime);
+ if (err)
+ return err;
+
+ raw_spin_rq_lock_irqsave(rq, flags);
+ if (runtime > rq->fair_server.dl_period)
+ err = -EINVAL;
+ else
+ rq->fair_server.dl_runtime = runtime;
+ raw_spin_rq_unlock_irqrestore(rq, flags);
+
+ if (err)
+ return err;
+
+ *ppos += cnt;
+ return cnt;
+}
+
+static int sched_fair_server_runtime_show(struct seq_file *m, void *v)
+{
+ unsigned long cpu = (unsigned long) m->private;
+ struct rq *rq = cpu_rq(cpu);
+
+ seq_printf(m, "%llu\n", rq->fair_server.dl_runtime);
+ return 0;
+}
+
+static int sched_fair_server_runtime_open(struct inode *inode, struct file *filp)
+{
+ return single_open(filp, sched_fair_server_runtime_show, inode->i_private);
+}
+
+static const struct file_operations fair_server_runtime_fops = {
+ .open = sched_fair_server_runtime_open,
+ .write = sched_fair_server_runtime_write,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static unsigned int fair_server_period_max = (1 << 22) * NSEC_PER_USEC; /* ~4 seconds */
+static unsigned int fair_server_period_min = (100) * NSEC_PER_USEC; /* 100 us */
+
+static ssize_t
+sched_fair_server_period_write(struct file *filp, const char __user *ubuf,
+ size_t cnt, loff_t *ppos)
+{
+ long cpu = (long) ((struct seq_file *) filp->private_data)->private;
+ struct rq *rq = cpu_rq(cpu);
+ unsigned long flags;
+ u64 period;
+ int err;
+
+ err = kstrtoull_from_user(ubuf, cnt, 10, &period);
+ if (err)
+ return err;
+
+ if (period < fair_server_period_min || period > fair_server_period_max)
+ return -EINVAL;
+
+ raw_spin_rq_lock_irqsave(rq, flags);
+ if (period < rq->fair_server.dl_runtime)
+ err = -EINVAL;
+ else
+ rq->fair_server.dl_period = period;
+ raw_spin_rq_unlock_irqrestore(rq, flags);
+
+ if (err)
+ return err;
+
+ *ppos += cnt;
+ return cnt;
+}
+
+static int sched_fair_server_period_show(struct seq_file *m, void *v)
+{
+ unsigned long cpu = (unsigned long) m->private;
+ struct rq *rq = cpu_rq(cpu);
+
+ seq_printf(m, "%llu\n", rq->fair_server.dl_period);
+ return 0;
+}
+
+static int sched_fair_server_period_open(struct inode *inode, struct file *filp)
+{
+ return single_open(filp, sched_fair_server_period_show, inode->i_private);
+}
+
+static const struct file_operations fair_server_period_fops = {
+ .open = sched_fair_server_period_open,
+ .write = sched_fair_server_period_write,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static ssize_t
+sched_fair_server_defer_write(struct file *filp, const char __user *ubuf,
+ size_t cnt, loff_t *ppos)
+{
+ long cpu = (long) ((struct seq_file *) filp->private_data)->private;
+ struct rq *rq = cpu_rq(cpu);
+ unsigned long flags;
+ u64 defer;
+ int err;
+
+ err = kstrtoull_from_user(ubuf, cnt, 10, &defer);
+ if (err)
+ return err;
+
+ if (defer < 0 || defer > 1)
+ return -EINVAL;
+
+ raw_spin_rq_lock_irqsave(rq, flags);
+ rq->fair_server_defer = defer;
+ raw_spin_rq_unlock_irqrestore(rq, flags);
+
+ *ppos += cnt;
+ return cnt;
+}
+
+static int sched_fair_server_defer_show(struct seq_file *m, void *v)
+{
+ unsigned long cpu = (unsigned long) m->private;
+ struct rq *rq = cpu_rq(cpu);
+
+ seq_printf(m, "%d\n", rq->fair_server_defer);
+ return 0;
+}
+
+static int sched_fair_server_defer_open(struct inode *inode, struct file *filp)
+{
+ return single_open(filp, sched_fair_server_defer_show, inode->i_private);
+}
+
+static const struct file_operations fair_server_defer_fops = {
+ .open = sched_fair_server_defer_open,
+ .write = sched_fair_server_defer_write,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
static struct dentry *debugfs_sched;
+void debugfs_fair_server_init(void)
+{
+ long cpu;
+ struct dentry *rq_dentry;
+
+ rq_dentry = debugfs_create_dir("rq", debugfs_sched);
+ if (!rq_dentry)
+ return;
+
+ for_each_possible_cpu(cpu) {
+ struct dentry *d_cpu;
+ char buf[32];
+
+ snprintf(buf, sizeof(buf), "cpu%ld", cpu);
+ d_cpu = debugfs_create_dir(buf, rq_dentry);
+
+ debugfs_create_file("fair_server_runtime", 0644, d_cpu, (void *) cpu, &fair_server_runtime_fops);
+ debugfs_create_file("fair_server_period", 0644, d_cpu, (void *) cpu, &fair_server_period_fops);
+ debugfs_create_file("fair_server_defer", 0644, d_cpu, (void *) cpu, &fair_server_defer_fops);
+ }
+}
+
static __init int sched_init_debug(void)
{
struct dentry __maybe_unused *numa;
@@ -374,6 +549,8 @@ static __init int sched_init_debug(void)
debugfs_create_file("debug", 0444, debugfs_sched, NULL, &sched_debug_fops);
+ debugfs_fair_server_init();
+
return 0;
}
late_initcall(sched_init_debug);
--
2.40.1
On Thu, Aug 31, 2023 at 10:28:58PM +0200, Daniel Bristot de Oliveira wrote:
> +static ssize_t
> +sched_fair_server_runtime_write(struct file *filp, const char __user *ubuf,
> + size_t cnt, loff_t *ppos)
> +{
> + long cpu = (long) ((struct seq_file *) filp->private_data)->private;
> + struct rq *rq = cpu_rq(cpu);
> + unsigned long flags;
> + u64 runtime;
> + int err;
> +
> + err = kstrtoull_from_user(ubuf, cnt, 10, &runtime);
> + if (err)
> + return err;
> +
> + raw_spin_rq_lock_irqsave(rq, flags);
> + if (runtime > rq->fair_server.dl_period)
> + err = -EINVAL;
> + else
> + rq->fair_server.dl_runtime = runtime;
> + raw_spin_rq_unlock_irqrestore(rq, flags);
> +
> + if (err)
> + return err;
> +
> + *ppos += cnt;
> + return cnt;
> +}
> +static ssize_t
> +sched_fair_server_period_write(struct file *filp, const char __user *ubuf,
> + size_t cnt, loff_t *ppos)
> +{
> + long cpu = (long) ((struct seq_file *) filp->private_data)->private;
> + struct rq *rq = cpu_rq(cpu);
> + unsigned long flags;
> + u64 period;
> + int err;
> +
> + err = kstrtoull_from_user(ubuf, cnt, 10, &period);
> + if (err)
> + return err;
> +
> + if (period < fair_server_period_min || period > fair_server_period_max)
> + return -EINVAL;
> +
> + raw_spin_rq_lock_irqsave(rq, flags);
> + if (period < rq->fair_server.dl_runtime)
> + err = -EINVAL;
> + else
> + rq->fair_server.dl_period = period;
> + raw_spin_rq_unlock_irqrestore(rq, flags);
> +
> + if (err)
> + return err;
> +
> + *ppos += cnt;
> + return cnt;
> +}
> +static ssize_t
> +sched_fair_server_defer_write(struct file *filp, const char __user *ubuf,
> + size_t cnt, loff_t *ppos)
> +{
> + long cpu = (long) ((struct seq_file *) filp->private_data)->private;
> + struct rq *rq = cpu_rq(cpu);
> + unsigned long flags;
> + u64 defer;
> + int err;
> +
> + err = kstrtoull_from_user(ubuf, cnt, 10, &defer);
> + if (err)
> + return err;
> +
> + if (defer < 0 || defer > 1)
> + return -EINVAL;
> +
> + raw_spin_rq_lock_irqsave(rq, flags);
> + rq->fair_server_defer = defer;
> + raw_spin_rq_unlock_irqrestore(rq, flags);
> +
> + *ppos += cnt;
> + return cnt;
> +}
Surely we can write a single function that does all of that with less
duplication?
Additionally, should not the deadline parameters be vetted by access
control before being accepted ?
Perhaps something like so:
static ssize_t
sched_fair_server_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos, enum dl_param param)
{
long cpu = (long) ((struct seq_file *) filp->private_data)->private;
struct rq *rq = cpu_rq(cpu);
u64 value;
err = kstrtoull_from_user(ubuf, cnt, 10, &value);
if (err)
return err;
scoped_guard (rq_lock_irqsave, rq) {
u64 runtime, deadline, period;
runtime = rq->fair_server.dl_runtime;
deadline = rq->fair_server.dl_deadline;
period = rq->fair_server.dl_period;
switch (param) {
case dl_runtime: runtime = value; break;
case dl_deadline: deadline = value; break;
case dl_period: period = value; break;
}
if (runtime > deadline ||
deadline > period ||
/* more stuff like access controll */)
return -EINVAL;
rq->fair_server.dl_runtime = runtime;
rq->fair_server.dl_deadline = deadline;
rq->fair_server.dl_period = period;
}
*ppos += cnt;
return cnt;
}
On 9/5/23 15:55, Peter Zijlstra wrote:
> On Thu, Aug 31, 2023 at 10:28:58PM +0200, Daniel Bristot de Oliveira wrote:
>> +static ssize_t
>> +sched_fair_server_runtime_write(struct file *filp, const char __user *ubuf,
>> + size_t cnt, loff_t *ppos)
>> +{
>> + long cpu = (long) ((struct seq_file *) filp->private_data)->private;
>> + struct rq *rq = cpu_rq(cpu);
>> + unsigned long flags;
>> + u64 runtime;
>> + int err;
>> +
>> + err = kstrtoull_from_user(ubuf, cnt, 10, &runtime);
>> + if (err)
>> + return err;
>> +
>> + raw_spin_rq_lock_irqsave(rq, flags);
>> + if (runtime > rq->fair_server.dl_period)
>> + err = -EINVAL;
>> + else
>> + rq->fair_server.dl_runtime = runtime;
>> + raw_spin_rq_unlock_irqrestore(rq, flags);
>> +
>> + if (err)
>> + return err;
>> +
>> + *ppos += cnt;
>> + return cnt;
>> +}
>
>> +static ssize_t
>> +sched_fair_server_period_write(struct file *filp, const char __user *ubuf,
>> + size_t cnt, loff_t *ppos)
>> +{
>> + long cpu = (long) ((struct seq_file *) filp->private_data)->private;
>> + struct rq *rq = cpu_rq(cpu);
>> + unsigned long flags;
>> + u64 period;
>> + int err;
>> +
>> + err = kstrtoull_from_user(ubuf, cnt, 10, &period);
>> + if (err)
>> + return err;
>> +
>> + if (period < fair_server_period_min || period > fair_server_period_max)
>> + return -EINVAL;
>> +
>> + raw_spin_rq_lock_irqsave(rq, flags);
>> + if (period < rq->fair_server.dl_runtime)
>> + err = -EINVAL;
>> + else
>> + rq->fair_server.dl_period = period;
>> + raw_spin_rq_unlock_irqrestore(rq, flags);
>> +
>> + if (err)
>> + return err;
>> +
>> + *ppos += cnt;
>> + return cnt;
>> +}
>
>> +static ssize_t
>> +sched_fair_server_defer_write(struct file *filp, const char __user *ubuf,
>> + size_t cnt, loff_t *ppos)
>> +{
>> + long cpu = (long) ((struct seq_file *) filp->private_data)->private;
>> + struct rq *rq = cpu_rq(cpu);
>> + unsigned long flags;
>> + u64 defer;
>> + int err;
>> +
>> + err = kstrtoull_from_user(ubuf, cnt, 10, &defer);
>> + if (err)
>> + return err;
>> +
>> + if (defer < 0 || defer > 1)
>> + return -EINVAL;
>> +
>> + raw_spin_rq_lock_irqsave(rq, flags);
>> + rq->fair_server_defer = defer;
>> + raw_spin_rq_unlock_irqrestore(rq, flags);
>> +
>> + *ppos += cnt;
>> + return cnt;
>> +}
>
> Surely we can write a single function that does all of that with less
> duplication?
I agree, I will use your code as starting point for that...
>
> Additionally, should not the deadline parameters be vetted by access
> control before being accepted ?
like security_task_getscheduler(p)? But we have no p...
I checked rt throttling, but it seems that it does not check. Do you have
a pointer?
-- Daniel
On Tue, Sep 05, 2023 at 06:17:26PM +0200, Daniel Bristot de Oliveira wrote: > > Additionally, should not the deadline parameters be vetted by access > > control before being accepted ? > > like security_task_getscheduler(p)? But we have no p... I was thinking sched_dl_overflow() or thereabout. That still runs on p, but I'm thikning that should be easily adapted to dl_se or somesuch.
On Wed, Sep 06, 2023 at 09:25:01AM +0200, Peter Zijlstra wrote: > On Tue, Sep 05, 2023 at 06:17:26PM +0200, Daniel Bristot de Oliveira wrote: > > > > Additionally, should not the deadline parameters be vetted by access > > > control before being accepted ? > > > > like security_task_getscheduler(p)? But we have no p... > > I was thinking sched_dl_overflow() or thereabout. That still runs on p, > but I'm thikning that should be easily adapted to dl_se or somesuch. Clearly my scrambled brain confused admission control and access control.
Hi Daniel,
kernel test robot noticed the following build warnings:
[auto build test WARNING on tip/sched/core]
[also build test WARNING on tip/master linus/master next-20230831]
[cannot apply to tip/auto-latest v6.5]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Daniel-Bristot-de-Oliveira/sched-Unify-runtime-accounting-across-classes/20230901-043307
base: tip/sched/core
patch link: https://lore.kernel.org/r/db775d65b18ddac4a75faad6761c6c2abf3efb78.1693510979.git.bristot%40kernel.org
patch subject: [PATCH v4 7/7] sched/fair: Fair server interface
config: m68k-allyesconfig (https://download.01.org/0day-ci/archive/20230901/202309010917.ryl6BbIf-lkp@intel.com/config)
compiler: m68k-linux-gcc (GCC) 13.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20230901/202309010917.ryl6BbIf-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202309010917.ryl6BbIf-lkp@intel.com/
All warnings (new ones prefixed by >>):
In file included from kernel/sched/build_utility.c:73:
>> kernel/sched/debug.c:386:56: warning: integer overflow in expression of type 'long int' results in '-100663296' [-Woverflow]
386 | static unsigned int fair_server_period_max = (1 << 22) * NSEC_PER_USEC; /* ~4 seconds */
| ^
>> kernel/sched/debug.c:491:6: warning: no previous prototype for 'debugfs_fair_server_init' [-Wmissing-prototypes]
491 | void debugfs_fair_server_init(void)
| ^~~~~~~~~~~~~~~~~~~~~~~~
vim +386 kernel/sched/debug.c
385
> 386 static unsigned int fair_server_period_max = (1 << 22) * NSEC_PER_USEC; /* ~4 seconds */
387 static unsigned int fair_server_period_min = (100) * NSEC_PER_USEC; /* 100 us */
388
389 static ssize_t
390 sched_fair_server_period_write(struct file *filp, const char __user *ubuf,
391 size_t cnt, loff_t *ppos)
392 {
393 long cpu = (long) ((struct seq_file *) filp->private_data)->private;
394 struct rq *rq = cpu_rq(cpu);
395 unsigned long flags;
396 u64 period;
397 int err;
398
399 err = kstrtoull_from_user(ubuf, cnt, 10, &period);
400 if (err)
401 return err;
402
403 if (period < fair_server_period_min || period > fair_server_period_max)
404 return -EINVAL;
405
406 raw_spin_rq_lock_irqsave(rq, flags);
407 if (period < rq->fair_server.dl_runtime)
408 err = -EINVAL;
409 else
410 rq->fair_server.dl_period = period;
411 raw_spin_rq_unlock_irqrestore(rq, flags);
412
413 if (err)
414 return err;
415
416 *ppos += cnt;
417 return cnt;
418 }
419
420 static int sched_fair_server_period_show(struct seq_file *m, void *v)
421 {
422 unsigned long cpu = (unsigned long) m->private;
423 struct rq *rq = cpu_rq(cpu);
424
425 seq_printf(m, "%llu\n", rq->fair_server.dl_period);
426 return 0;
427 }
428
429 static int sched_fair_server_period_open(struct inode *inode, struct file *filp)
430 {
431 return single_open(filp, sched_fair_server_period_show, inode->i_private);
432 }
433
434 static const struct file_operations fair_server_period_fops = {
435 .open = sched_fair_server_period_open,
436 .write = sched_fair_server_period_write,
437 .read = seq_read,
438 .llseek = seq_lseek,
439 .release = single_release,
440 };
441
442 static ssize_t
443 sched_fair_server_defer_write(struct file *filp, const char __user *ubuf,
444 size_t cnt, loff_t *ppos)
445 {
446 long cpu = (long) ((struct seq_file *) filp->private_data)->private;
447 struct rq *rq = cpu_rq(cpu);
448 unsigned long flags;
449 u64 defer;
450 int err;
451
452 err = kstrtoull_from_user(ubuf, cnt, 10, &defer);
453 if (err)
454 return err;
455
456 if (defer < 0 || defer > 1)
457 return -EINVAL;
458
459 raw_spin_rq_lock_irqsave(rq, flags);
460 rq->fair_server_defer = defer;
461 raw_spin_rq_unlock_irqrestore(rq, flags);
462
463 *ppos += cnt;
464 return cnt;
465 }
466
467 static int sched_fair_server_defer_show(struct seq_file *m, void *v)
468 {
469 unsigned long cpu = (unsigned long) m->private;
470 struct rq *rq = cpu_rq(cpu);
471
472 seq_printf(m, "%d\n", rq->fair_server_defer);
473 return 0;
474 }
475
476 static int sched_fair_server_defer_open(struct inode *inode, struct file *filp)
477 {
478 return single_open(filp, sched_fair_server_defer_show, inode->i_private);
479 }
480
481 static const struct file_operations fair_server_defer_fops = {
482 .open = sched_fair_server_defer_open,
483 .write = sched_fair_server_defer_write,
484 .read = seq_read,
485 .llseek = seq_lseek,
486 .release = single_release,
487 };
488
489 static struct dentry *debugfs_sched;
490
> 491 void debugfs_fair_server_init(void)
492 {
493 long cpu;
494 struct dentry *rq_dentry;
495
496 rq_dentry = debugfs_create_dir("rq", debugfs_sched);
497 if (!rq_dentry)
498 return;
499
500 for_each_possible_cpu(cpu) {
501 struct dentry *d_cpu;
502 char buf[32];
503
504 snprintf(buf, sizeof(buf), "cpu%ld", cpu);
505 d_cpu = debugfs_create_dir(buf, rq_dentry);
506
507 debugfs_create_file("fair_server_runtime", 0644, d_cpu, (void *) cpu, &fair_server_runtime_fops);
508 debugfs_create_file("fair_server_period", 0644, d_cpu, (void *) cpu, &fair_server_period_fops);
509 debugfs_create_file("fair_server_defer", 0644, d_cpu, (void *) cpu, &fair_server_defer_fops);
510 }
511 }
512
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
© 2016 - 2026 Red Hat, Inc.