Skip to content

Commit b4fb015

Browse files
koct9iIngo Molnar
authored andcommitted
sched/rt: Optimize checking group RT scheduler constraints
Group RT scheduler contains protection against setting zero runtime for cgroup with RT tasks. Right now function tg_set_rt_bandwidth() iterates over all CPU cgroups and calls tg_has_rt_tasks() for any cgroup which runtime is zero (not only for changed one). Default RT runtime is zero, thus tg_has_rt_tasks() will is called for almost at CPU cgroups. This protection already is slightly racy: runtime limit could be changed between cpu_cgroup_can_attach() and cpu_cgroup_attach() because changing cgroup attribute does not lock cgroup_mutex while attach does not lock rt_constraints_mutex. Changing task scheduler class also races with changing rt runtime: check in __sched_setscheduler() isn't protected. Function tg_has_rt_tasks() iterates over all threads in the system. This gives NR_CGROUPS * NR_TASKS operations under single tasklist_lock locked for read tg_set_rt_bandwidth(). Any concurrent attempt of locking tasklist_lock for write (for example fork) will stuck with disabled irqs. This patch makes two optimizations: 1) Remove locking tasklist_lock and iterate only tasks in cgroup 2) Call tg_has_rt_tasks() iff rt runtime changes from non-zero to zero All changed code is under CONFIG_RT_GROUP_SCHED. Testcase: # mkdir /sys/fs/cgroup/cpu/test{1..10000} # echo 0 | tee /sys/fs/cgroup/cpu/test*/cpu.rt_runtime_us At the same time without patch fork time will be >100ms: # perf trace -e clone --duration 100 stress-ng --fork 1 Also remote ping will show timings >100ms caused by irq latency. Signed-off-by: Konstantin Khlebnikov <[email protected]> Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Signed-off-by: Ingo Molnar <[email protected]> Link: https://lkml.kernel.org/r/157996383820.4651.11292439232549211693.stgit@buzz
1 parent bec2860 commit b4fb015

File tree

1 file changed

+11
-13
lines changed

1 file changed

+11
-13
lines changed

kernel/sched/rt.c

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2449,23 +2449,24 @@ const struct sched_class rt_sched_class = {
24492449
*/
24502450
static DEFINE_MUTEX(rt_constraints_mutex);
24512451

2452-
/* Must be called with tasklist_lock held */
24532452
static inline int tg_has_rt_tasks(struct task_group *tg)
24542453
{
2455-
struct task_struct *g, *p;
2454+
struct task_struct *task;
2455+
struct css_task_iter it;
2456+
int ret = 0;
24562457

24572458
/*
24582459
* Autogroups do not have RT tasks; see autogroup_create().
24592460
*/
24602461
if (task_group_is_autogroup(tg))
24612462
return 0;
24622463

2463-
for_each_process_thread(g, p) {
2464-
if (rt_task(p) && task_group(p) == tg)
2465-
return 1;
2466-
}
2464+
css_task_iter_start(&tg->css, 0, &it);
2465+
while (!ret && (task = css_task_iter_next(&it)))
2466+
ret |= rt_task(task);
2467+
css_task_iter_end(&it);
24672468

2468-
return 0;
2469+
return ret;
24692470
}
24702471

24712472
struct rt_schedulable_data {
@@ -2496,9 +2497,10 @@ static int tg_rt_schedulable(struct task_group *tg, void *data)
24962497
return -EINVAL;
24972498

24982499
/*
2499-
* Ensure we don't starve existing RT tasks.
2500+
* Ensure we don't starve existing RT tasks if runtime turns zero.
25002501
*/
2501-
if (rt_bandwidth_enabled() && !runtime && tg_has_rt_tasks(tg))
2502+
if (rt_bandwidth_enabled() && !runtime &&
2503+
tg->rt_bandwidth.rt_runtime && tg_has_rt_tasks(tg))
25022504
return -EBUSY;
25032505

25042506
total = to_ratio(period, runtime);
@@ -2564,7 +2566,6 @@ static int tg_set_rt_bandwidth(struct task_group *tg,
25642566
return -EINVAL;
25652567

25662568
mutex_lock(&rt_constraints_mutex);
2567-
read_lock(&tasklist_lock);
25682569
err = __rt_schedulable(tg, rt_period, rt_runtime);
25692570
if (err)
25702571
goto unlock;
@@ -2582,7 +2583,6 @@ static int tg_set_rt_bandwidth(struct task_group *tg,
25822583
}
25832584
raw_spin_unlock_irq(&tg->rt_bandwidth.rt_runtime_lock);
25842585
unlock:
2585-
read_unlock(&tasklist_lock);
25862586
mutex_unlock(&rt_constraints_mutex);
25872587

25882588
return err;
@@ -2641,9 +2641,7 @@ static int sched_rt_global_constraints(void)
26412641
int ret = 0;
26422642

26432643
mutex_lock(&rt_constraints_mutex);
2644-
read_lock(&tasklist_lock);
26452644
ret = __rt_schedulable(NULL, 0, 0);
2646-
read_unlock(&tasklist_lock);
26472645
mutex_unlock(&rt_constraints_mutex);
26482646

26492647
return ret;

0 commit comments

Comments
 (0)