sched/rt: Move RT related code from sched/core.c to sched/rt.c
This helps making sched/core.c smaller and hopefully easier to understand and maintain. Signed-off-by: Nicolas Pitre <nico@linaro.org> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Link: http://lkml.kernel.org/r/20170621182203.30626-3-nicolas.pitre@linaro.org Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
parent
06a76fe08d
commit
8887cd9903
|
@ -6224,321 +6224,6 @@ void sched_move_task(struct task_struct *tsk)
|
||||||
|
|
||||||
task_rq_unlock(rq, tsk, &rf);
|
task_rq_unlock(rq, tsk, &rf);
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_CGROUP_SCHED */
|
|
||||||
|
|
||||||
#ifdef CONFIG_RT_GROUP_SCHED
|
|
||||||
/*
|
|
||||||
* Ensure that the real time constraints are schedulable.
|
|
||||||
*/
|
|
||||||
static DEFINE_MUTEX(rt_constraints_mutex);
|
|
||||||
|
|
||||||
/* Must be called with tasklist_lock held */
|
|
||||||
static inline int tg_has_rt_tasks(struct task_group *tg)
|
|
||||||
{
|
|
||||||
struct task_struct *g, *p;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Autogroups do not have RT tasks; see autogroup_create().
|
|
||||||
*/
|
|
||||||
if (task_group_is_autogroup(tg))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
for_each_process_thread(g, p) {
|
|
||||||
if (rt_task(p) && task_group(p) == tg)
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct rt_schedulable_data {
|
|
||||||
struct task_group *tg;
|
|
||||||
u64 rt_period;
|
|
||||||
u64 rt_runtime;
|
|
||||||
};
|
|
||||||
|
|
||||||
static int tg_rt_schedulable(struct task_group *tg, void *data)
|
|
||||||
{
|
|
||||||
struct rt_schedulable_data *d = data;
|
|
||||||
struct task_group *child;
|
|
||||||
unsigned long total, sum = 0;
|
|
||||||
u64 period, runtime;
|
|
||||||
|
|
||||||
period = ktime_to_ns(tg->rt_bandwidth.rt_period);
|
|
||||||
runtime = tg->rt_bandwidth.rt_runtime;
|
|
||||||
|
|
||||||
if (tg == d->tg) {
|
|
||||||
period = d->rt_period;
|
|
||||||
runtime = d->rt_runtime;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Cannot have more runtime than the period.
|
|
||||||
*/
|
|
||||||
if (runtime > period && runtime != RUNTIME_INF)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Ensure we don't starve existing RT tasks.
|
|
||||||
*/
|
|
||||||
if (rt_bandwidth_enabled() && !runtime && tg_has_rt_tasks(tg))
|
|
||||||
return -EBUSY;
|
|
||||||
|
|
||||||
total = to_ratio(period, runtime);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Nobody can have more than the global setting allows.
|
|
||||||
*/
|
|
||||||
if (total > to_ratio(global_rt_period(), global_rt_runtime()))
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The sum of our children's runtime should not exceed our own.
|
|
||||||
*/
|
|
||||||
list_for_each_entry_rcu(child, &tg->children, siblings) {
|
|
||||||
period = ktime_to_ns(child->rt_bandwidth.rt_period);
|
|
||||||
runtime = child->rt_bandwidth.rt_runtime;
|
|
||||||
|
|
||||||
if (child == d->tg) {
|
|
||||||
period = d->rt_period;
|
|
||||||
runtime = d->rt_runtime;
|
|
||||||
}
|
|
||||||
|
|
||||||
sum += to_ratio(period, runtime);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sum > total)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int __rt_schedulable(struct task_group *tg, u64 period, u64 runtime)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
struct rt_schedulable_data data = {
|
|
||||||
.tg = tg,
|
|
||||||
.rt_period = period,
|
|
||||||
.rt_runtime = runtime,
|
|
||||||
};
|
|
||||||
|
|
||||||
rcu_read_lock();
|
|
||||||
ret = walk_tg_tree(tg_rt_schedulable, tg_nop, &data);
|
|
||||||
rcu_read_unlock();
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int tg_set_rt_bandwidth(struct task_group *tg,
|
|
||||||
u64 rt_period, u64 rt_runtime)
|
|
||||||
{
|
|
||||||
int i, err = 0;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Disallowing the root group RT runtime is BAD, it would disallow the
|
|
||||||
* kernel creating (and or operating) RT threads.
|
|
||||||
*/
|
|
||||||
if (tg == &root_task_group && rt_runtime == 0)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
/* No period doesn't make any sense. */
|
|
||||||
if (rt_period == 0)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
mutex_lock(&rt_constraints_mutex);
|
|
||||||
read_lock(&tasklist_lock);
|
|
||||||
err = __rt_schedulable(tg, rt_period, rt_runtime);
|
|
||||||
if (err)
|
|
||||||
goto unlock;
|
|
||||||
|
|
||||||
raw_spin_lock_irq(&tg->rt_bandwidth.rt_runtime_lock);
|
|
||||||
tg->rt_bandwidth.rt_period = ns_to_ktime(rt_period);
|
|
||||||
tg->rt_bandwidth.rt_runtime = rt_runtime;
|
|
||||||
|
|
||||||
for_each_possible_cpu(i) {
|
|
||||||
struct rt_rq *rt_rq = tg->rt_rq[i];
|
|
||||||
|
|
||||||
raw_spin_lock(&rt_rq->rt_runtime_lock);
|
|
||||||
rt_rq->rt_runtime = rt_runtime;
|
|
||||||
raw_spin_unlock(&rt_rq->rt_runtime_lock);
|
|
||||||
}
|
|
||||||
raw_spin_unlock_irq(&tg->rt_bandwidth.rt_runtime_lock);
|
|
||||||
unlock:
|
|
||||||
read_unlock(&tasklist_lock);
|
|
||||||
mutex_unlock(&rt_constraints_mutex);
|
|
||||||
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int sched_group_set_rt_runtime(struct task_group *tg, long rt_runtime_us)
|
|
||||||
{
|
|
||||||
u64 rt_runtime, rt_period;
|
|
||||||
|
|
||||||
rt_period = ktime_to_ns(tg->rt_bandwidth.rt_period);
|
|
||||||
rt_runtime = (u64)rt_runtime_us * NSEC_PER_USEC;
|
|
||||||
if (rt_runtime_us < 0)
|
|
||||||
rt_runtime = RUNTIME_INF;
|
|
||||||
|
|
||||||
return tg_set_rt_bandwidth(tg, rt_period, rt_runtime);
|
|
||||||
}
|
|
||||||
|
|
||||||
static long sched_group_rt_runtime(struct task_group *tg)
|
|
||||||
{
|
|
||||||
u64 rt_runtime_us;
|
|
||||||
|
|
||||||
if (tg->rt_bandwidth.rt_runtime == RUNTIME_INF)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
rt_runtime_us = tg->rt_bandwidth.rt_runtime;
|
|
||||||
do_div(rt_runtime_us, NSEC_PER_USEC);
|
|
||||||
return rt_runtime_us;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int sched_group_set_rt_period(struct task_group *tg, u64 rt_period_us)
|
|
||||||
{
|
|
||||||
u64 rt_runtime, rt_period;
|
|
||||||
|
|
||||||
rt_period = rt_period_us * NSEC_PER_USEC;
|
|
||||||
rt_runtime = tg->rt_bandwidth.rt_runtime;
|
|
||||||
|
|
||||||
return tg_set_rt_bandwidth(tg, rt_period, rt_runtime);
|
|
||||||
}
|
|
||||||
|
|
||||||
static long sched_group_rt_period(struct task_group *tg)
|
|
||||||
{
|
|
||||||
u64 rt_period_us;
|
|
||||||
|
|
||||||
rt_period_us = ktime_to_ns(tg->rt_bandwidth.rt_period);
|
|
||||||
do_div(rt_period_us, NSEC_PER_USEC);
|
|
||||||
return rt_period_us;
|
|
||||||
}
|
|
||||||
#endif /* CONFIG_RT_GROUP_SCHED */
|
|
||||||
|
|
||||||
#ifdef CONFIG_RT_GROUP_SCHED
|
|
||||||
static int sched_rt_global_constraints(void)
|
|
||||||
{
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
mutex_lock(&rt_constraints_mutex);
|
|
||||||
read_lock(&tasklist_lock);
|
|
||||||
ret = __rt_schedulable(NULL, 0, 0);
|
|
||||||
read_unlock(&tasklist_lock);
|
|
||||||
mutex_unlock(&rt_constraints_mutex);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int sched_rt_can_attach(struct task_group *tg, struct task_struct *tsk)
|
|
||||||
{
|
|
||||||
/* Don't accept realtime tasks when there is no way for them to run */
|
|
||||||
if (rt_task(tsk) && tg->rt_bandwidth.rt_runtime == 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else /* !CONFIG_RT_GROUP_SCHED */
|
|
||||||
static int sched_rt_global_constraints(void)
|
|
||||||
{
|
|
||||||
unsigned long flags;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
raw_spin_lock_irqsave(&def_rt_bandwidth.rt_runtime_lock, flags);
|
|
||||||
for_each_possible_cpu(i) {
|
|
||||||
struct rt_rq *rt_rq = &cpu_rq(i)->rt;
|
|
||||||
|
|
||||||
raw_spin_lock(&rt_rq->rt_runtime_lock);
|
|
||||||
rt_rq->rt_runtime = global_rt_runtime();
|
|
||||||
raw_spin_unlock(&rt_rq->rt_runtime_lock);
|
|
||||||
}
|
|
||||||
raw_spin_unlock_irqrestore(&def_rt_bandwidth.rt_runtime_lock, flags);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif /* CONFIG_RT_GROUP_SCHED */
|
|
||||||
|
|
||||||
static int sched_rt_global_validate(void)
|
|
||||||
{
|
|
||||||
if (sysctl_sched_rt_period <= 0)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if ((sysctl_sched_rt_runtime != RUNTIME_INF) &&
|
|
||||||
(sysctl_sched_rt_runtime > sysctl_sched_rt_period))
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void sched_rt_do_global(void)
|
|
||||||
{
|
|
||||||
def_rt_bandwidth.rt_runtime = global_rt_runtime();
|
|
||||||
def_rt_bandwidth.rt_period = ns_to_ktime(global_rt_period());
|
|
||||||
}
|
|
||||||
|
|
||||||
int sched_rt_handler(struct ctl_table *table, int write,
|
|
||||||
void __user *buffer, size_t *lenp,
|
|
||||||
loff_t *ppos)
|
|
||||||
{
|
|
||||||
int old_period, old_runtime;
|
|
||||||
static DEFINE_MUTEX(mutex);
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
mutex_lock(&mutex);
|
|
||||||
old_period = sysctl_sched_rt_period;
|
|
||||||
old_runtime = sysctl_sched_rt_runtime;
|
|
||||||
|
|
||||||
ret = proc_dointvec(table, write, buffer, lenp, ppos);
|
|
||||||
|
|
||||||
if (!ret && write) {
|
|
||||||
ret = sched_rt_global_validate();
|
|
||||||
if (ret)
|
|
||||||
goto undo;
|
|
||||||
|
|
||||||
ret = sched_dl_global_validate();
|
|
||||||
if (ret)
|
|
||||||
goto undo;
|
|
||||||
|
|
||||||
ret = sched_rt_global_constraints();
|
|
||||||
if (ret)
|
|
||||||
goto undo;
|
|
||||||
|
|
||||||
sched_rt_do_global();
|
|
||||||
sched_dl_do_global();
|
|
||||||
}
|
|
||||||
if (0) {
|
|
||||||
undo:
|
|
||||||
sysctl_sched_rt_period = old_period;
|
|
||||||
sysctl_sched_rt_runtime = old_runtime;
|
|
||||||
}
|
|
||||||
mutex_unlock(&mutex);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int sched_rr_handler(struct ctl_table *table, int write,
|
|
||||||
void __user *buffer, size_t *lenp,
|
|
||||||
loff_t *ppos)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
static DEFINE_MUTEX(mutex);
|
|
||||||
|
|
||||||
mutex_lock(&mutex);
|
|
||||||
ret = proc_dointvec(table, write, buffer, lenp, ppos);
|
|
||||||
/*
|
|
||||||
* Make sure that internally we keep jiffies.
|
|
||||||
* Also, writing zero resets the timeslice to default:
|
|
||||||
*/
|
|
||||||
if (!ret && write) {
|
|
||||||
sched_rr_timeslice =
|
|
||||||
sysctl_sched_rr_timeslice <= 0 ? RR_TIMESLICE :
|
|
||||||
msecs_to_jiffies(sysctl_sched_rr_timeslice);
|
|
||||||
}
|
|
||||||
mutex_unlock(&mutex);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef CONFIG_CGROUP_SCHED
|
|
||||||
|
|
||||||
static inline struct task_group *css_tg(struct cgroup_subsys_state *css)
|
static inline struct task_group *css_tg(struct cgroup_subsys_state *css)
|
||||||
{
|
{
|
||||||
|
|
|
@ -2449,6 +2449,316 @@ const struct sched_class rt_sched_class = {
|
||||||
.update_curr = update_curr_rt,
|
.update_curr = update_curr_rt,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef CONFIG_RT_GROUP_SCHED
|
||||||
|
/*
|
||||||
|
* Ensure that the real time constraints are schedulable.
|
||||||
|
*/
|
||||||
|
static DEFINE_MUTEX(rt_constraints_mutex);
|
||||||
|
|
||||||
|
/* Must be called with tasklist_lock held */
|
||||||
|
static inline int tg_has_rt_tasks(struct task_group *tg)
|
||||||
|
{
|
||||||
|
struct task_struct *g, *p;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Autogroups do not have RT tasks; see autogroup_create().
|
||||||
|
*/
|
||||||
|
if (task_group_is_autogroup(tg))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
for_each_process_thread(g, p) {
|
||||||
|
if (rt_task(p) && task_group(p) == tg)
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct rt_schedulable_data {
|
||||||
|
struct task_group *tg;
|
||||||
|
u64 rt_period;
|
||||||
|
u64 rt_runtime;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int tg_rt_schedulable(struct task_group *tg, void *data)
|
||||||
|
{
|
||||||
|
struct rt_schedulable_data *d = data;
|
||||||
|
struct task_group *child;
|
||||||
|
unsigned long total, sum = 0;
|
||||||
|
u64 period, runtime;
|
||||||
|
|
||||||
|
period = ktime_to_ns(tg->rt_bandwidth.rt_period);
|
||||||
|
runtime = tg->rt_bandwidth.rt_runtime;
|
||||||
|
|
||||||
|
if (tg == d->tg) {
|
||||||
|
period = d->rt_period;
|
||||||
|
runtime = d->rt_runtime;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Cannot have more runtime than the period.
|
||||||
|
*/
|
||||||
|
if (runtime > period && runtime != RUNTIME_INF)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ensure we don't starve existing RT tasks.
|
||||||
|
*/
|
||||||
|
if (rt_bandwidth_enabled() && !runtime && tg_has_rt_tasks(tg))
|
||||||
|
return -EBUSY;
|
||||||
|
|
||||||
|
total = to_ratio(period, runtime);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Nobody can have more than the global setting allows.
|
||||||
|
*/
|
||||||
|
if (total > to_ratio(global_rt_period(), global_rt_runtime()))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The sum of our children's runtime should not exceed our own.
|
||||||
|
*/
|
||||||
|
list_for_each_entry_rcu(child, &tg->children, siblings) {
|
||||||
|
period = ktime_to_ns(child->rt_bandwidth.rt_period);
|
||||||
|
runtime = child->rt_bandwidth.rt_runtime;
|
||||||
|
|
||||||
|
if (child == d->tg) {
|
||||||
|
period = d->rt_period;
|
||||||
|
runtime = d->rt_runtime;
|
||||||
|
}
|
||||||
|
|
||||||
|
sum += to_ratio(period, runtime);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sum > total)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __rt_schedulable(struct task_group *tg, u64 period, u64 runtime)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
struct rt_schedulable_data data = {
|
||||||
|
.tg = tg,
|
||||||
|
.rt_period = period,
|
||||||
|
.rt_runtime = runtime,
|
||||||
|
};
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
ret = walk_tg_tree(tg_rt_schedulable, tg_nop, &data);
|
||||||
|
rcu_read_unlock();
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tg_set_rt_bandwidth(struct task_group *tg,
|
||||||
|
u64 rt_period, u64 rt_runtime)
|
||||||
|
{
|
||||||
|
int i, err = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Disallowing the root group RT runtime is BAD, it would disallow the
|
||||||
|
* kernel creating (and or operating) RT threads.
|
||||||
|
*/
|
||||||
|
if (tg == &root_task_group && rt_runtime == 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
/* No period doesn't make any sense. */
|
||||||
|
if (rt_period == 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
mutex_lock(&rt_constraints_mutex);
|
||||||
|
read_lock(&tasklist_lock);
|
||||||
|
err = __rt_schedulable(tg, rt_period, rt_runtime);
|
||||||
|
if (err)
|
||||||
|
goto unlock;
|
||||||
|
|
||||||
|
raw_spin_lock_irq(&tg->rt_bandwidth.rt_runtime_lock);
|
||||||
|
tg->rt_bandwidth.rt_period = ns_to_ktime(rt_period);
|
||||||
|
tg->rt_bandwidth.rt_runtime = rt_runtime;
|
||||||
|
|
||||||
|
for_each_possible_cpu(i) {
|
||||||
|
struct rt_rq *rt_rq = tg->rt_rq[i];
|
||||||
|
|
||||||
|
raw_spin_lock(&rt_rq->rt_runtime_lock);
|
||||||
|
rt_rq->rt_runtime = rt_runtime;
|
||||||
|
raw_spin_unlock(&rt_rq->rt_runtime_lock);
|
||||||
|
}
|
||||||
|
raw_spin_unlock_irq(&tg->rt_bandwidth.rt_runtime_lock);
|
||||||
|
unlock:
|
||||||
|
read_unlock(&tasklist_lock);
|
||||||
|
mutex_unlock(&rt_constraints_mutex);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sched_group_set_rt_runtime(struct task_group *tg, long rt_runtime_us)
|
||||||
|
{
|
||||||
|
u64 rt_runtime, rt_period;
|
||||||
|
|
||||||
|
rt_period = ktime_to_ns(tg->rt_bandwidth.rt_period);
|
||||||
|
rt_runtime = (u64)rt_runtime_us * NSEC_PER_USEC;
|
||||||
|
if (rt_runtime_us < 0)
|
||||||
|
rt_runtime = RUNTIME_INF;
|
||||||
|
|
||||||
|
return tg_set_rt_bandwidth(tg, rt_period, rt_runtime);
|
||||||
|
}
|
||||||
|
|
||||||
|
long sched_group_rt_runtime(struct task_group *tg)
|
||||||
|
{
|
||||||
|
u64 rt_runtime_us;
|
||||||
|
|
||||||
|
if (tg->rt_bandwidth.rt_runtime == RUNTIME_INF)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
rt_runtime_us = tg->rt_bandwidth.rt_runtime;
|
||||||
|
do_div(rt_runtime_us, NSEC_PER_USEC);
|
||||||
|
return rt_runtime_us;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sched_group_set_rt_period(struct task_group *tg, u64 rt_period_us)
|
||||||
|
{
|
||||||
|
u64 rt_runtime, rt_period;
|
||||||
|
|
||||||
|
rt_period = rt_period_us * NSEC_PER_USEC;
|
||||||
|
rt_runtime = tg->rt_bandwidth.rt_runtime;
|
||||||
|
|
||||||
|
return tg_set_rt_bandwidth(tg, rt_period, rt_runtime);
|
||||||
|
}
|
||||||
|
|
||||||
|
long sched_group_rt_period(struct task_group *tg)
|
||||||
|
{
|
||||||
|
u64 rt_period_us;
|
||||||
|
|
||||||
|
rt_period_us = ktime_to_ns(tg->rt_bandwidth.rt_period);
|
||||||
|
do_div(rt_period_us, NSEC_PER_USEC);
|
||||||
|
return rt_period_us;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sched_rt_global_constraints(void)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
mutex_lock(&rt_constraints_mutex);
|
||||||
|
read_lock(&tasklist_lock);
|
||||||
|
ret = __rt_schedulable(NULL, 0, 0);
|
||||||
|
read_unlock(&tasklist_lock);
|
||||||
|
mutex_unlock(&rt_constraints_mutex);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sched_rt_can_attach(struct task_group *tg, struct task_struct *tsk)
|
||||||
|
{
|
||||||
|
/* Don't accept realtime tasks when there is no way for them to run */
|
||||||
|
if (rt_task(tsk) && tg->rt_bandwidth.rt_runtime == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else /* !CONFIG_RT_GROUP_SCHED */
|
||||||
|
static int sched_rt_global_constraints(void)
|
||||||
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
raw_spin_lock_irqsave(&def_rt_bandwidth.rt_runtime_lock, flags);
|
||||||
|
for_each_possible_cpu(i) {
|
||||||
|
struct rt_rq *rt_rq = &cpu_rq(i)->rt;
|
||||||
|
|
||||||
|
raw_spin_lock(&rt_rq->rt_runtime_lock);
|
||||||
|
rt_rq->rt_runtime = global_rt_runtime();
|
||||||
|
raw_spin_unlock(&rt_rq->rt_runtime_lock);
|
||||||
|
}
|
||||||
|
raw_spin_unlock_irqrestore(&def_rt_bandwidth.rt_runtime_lock, flags);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_RT_GROUP_SCHED */
|
||||||
|
|
||||||
|
static int sched_rt_global_validate(void)
|
||||||
|
{
|
||||||
|
if (sysctl_sched_rt_period <= 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if ((sysctl_sched_rt_runtime != RUNTIME_INF) &&
|
||||||
|
(sysctl_sched_rt_runtime > sysctl_sched_rt_period))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sched_rt_do_global(void)
|
||||||
|
{
|
||||||
|
def_rt_bandwidth.rt_runtime = global_rt_runtime();
|
||||||
|
def_rt_bandwidth.rt_period = ns_to_ktime(global_rt_period());
|
||||||
|
}
|
||||||
|
|
||||||
|
int sched_rt_handler(struct ctl_table *table, int write,
|
||||||
|
void __user *buffer, size_t *lenp,
|
||||||
|
loff_t *ppos)
|
||||||
|
{
|
||||||
|
int old_period, old_runtime;
|
||||||
|
static DEFINE_MUTEX(mutex);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
mutex_lock(&mutex);
|
||||||
|
old_period = sysctl_sched_rt_period;
|
||||||
|
old_runtime = sysctl_sched_rt_runtime;
|
||||||
|
|
||||||
|
ret = proc_dointvec(table, write, buffer, lenp, ppos);
|
||||||
|
|
||||||
|
if (!ret && write) {
|
||||||
|
ret = sched_rt_global_validate();
|
||||||
|
if (ret)
|
||||||
|
goto undo;
|
||||||
|
|
||||||
|
ret = sched_dl_global_validate();
|
||||||
|
if (ret)
|
||||||
|
goto undo;
|
||||||
|
|
||||||
|
ret = sched_rt_global_constraints();
|
||||||
|
if (ret)
|
||||||
|
goto undo;
|
||||||
|
|
||||||
|
sched_rt_do_global();
|
||||||
|
sched_dl_do_global();
|
||||||
|
}
|
||||||
|
if (0) {
|
||||||
|
undo:
|
||||||
|
sysctl_sched_rt_period = old_period;
|
||||||
|
sysctl_sched_rt_runtime = old_runtime;
|
||||||
|
}
|
||||||
|
mutex_unlock(&mutex);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sched_rr_handler(struct ctl_table *table, int write,
|
||||||
|
void __user *buffer, size_t *lenp,
|
||||||
|
loff_t *ppos)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
static DEFINE_MUTEX(mutex);
|
||||||
|
|
||||||
|
mutex_lock(&mutex);
|
||||||
|
ret = proc_dointvec(table, write, buffer, lenp, ppos);
|
||||||
|
/*
|
||||||
|
* Make sure that internally we keep jiffies.
|
||||||
|
* Also, writing zero resets the timeslice to default:
|
||||||
|
*/
|
||||||
|
if (!ret && write) {
|
||||||
|
sched_rr_timeslice =
|
||||||
|
sysctl_sched_rr_timeslice <= 0 ? RR_TIMESLICE :
|
||||||
|
msecs_to_jiffies(sysctl_sched_rr_timeslice);
|
||||||
|
}
|
||||||
|
mutex_unlock(&mutex);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_SCHED_DEBUG
|
#ifdef CONFIG_SCHED_DEBUG
|
||||||
extern void print_rt_rq(struct seq_file *m, int cpu, struct rt_rq *rt_rq);
|
extern void print_rt_rq(struct seq_file *m, int cpu, struct rt_rq *rt_rq);
|
||||||
|
|
||||||
|
|
|
@ -383,6 +383,11 @@ extern int alloc_rt_sched_group(struct task_group *tg, struct task_group *parent
|
||||||
extern void init_tg_rt_entry(struct task_group *tg, struct rt_rq *rt_rq,
|
extern void init_tg_rt_entry(struct task_group *tg, struct rt_rq *rt_rq,
|
||||||
struct sched_rt_entity *rt_se, int cpu,
|
struct sched_rt_entity *rt_se, int cpu,
|
||||||
struct sched_rt_entity *parent);
|
struct sched_rt_entity *parent);
|
||||||
|
extern int sched_group_set_rt_runtime(struct task_group *tg, long rt_runtime_us);
|
||||||
|
extern int sched_group_set_rt_period(struct task_group *tg, u64 rt_period_us);
|
||||||
|
extern long sched_group_rt_runtime(struct task_group *tg);
|
||||||
|
extern long sched_group_rt_period(struct task_group *tg);
|
||||||
|
extern int sched_rt_can_attach(struct task_group *tg, struct task_struct *tsk);
|
||||||
|
|
||||||
extern struct task_group *sched_create_group(struct task_group *parent);
|
extern struct task_group *sched_create_group(struct task_group *parent);
|
||||||
extern void sched_online_group(struct task_group *tg,
|
extern void sched_online_group(struct task_group *tg,
|
||||||
|
|
Loading…
Reference in New Issue