diff options
author | Kirill Tkhai <ktkhai@parallels.com> | 2014-03-06 04:32:01 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2014-03-11 07:05:39 -0400 |
commit | 4c6c4e38c4e9a454889298dcc498174968d14a09 (patch) | |
tree | ffb6a22c1f3a58667b3c745fe055b6dab3065443 | |
parent | e4aa358b6c23f98b2715594f6b1e9a4996a55f04 (diff) |
sched/core: Fix endless loop in pick_next_task()
1) Single cpu machine case.
When rq has only RT tasks, but no one of them can be picked
because of throttling, we enter in endless loop.
pick_next_task_{dl,rt} return NULL.
In pick_next_task_fair() we permanently go to retry
if (rq->nr_running != rq->cfs.h_nr_running)
return RETRY_TASK;
(rq->nr_running is not being decremented when rt_rq becomes
throttled).
No chances to unthrottle any rt_rq or to wake fair here,
because of rq is locked permanently and interrupts are
disabled.
2) In case of SMP this can cause a hang too. Although we unlock
rq in idle_balance(), interrupts are still disabled.
The solution is to check for available tasks in DL and RT
classes instead of checking for sum.
Signed-off-by: Kirill Tkhai <ktkhai@parallels.com>
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1394098321.19290.11.camel@tkhai
Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r-- | kernel/sched/fair.c | 4 | ||||
-rw-r--r-- | kernel/sched/rt.c | 10 | ||||
-rw-r--r-- | kernel/sched/sched.h | 12 |
3 files changed, 15 insertions, 11 deletions
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index b956e70fc503..10db4a87ad72 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c | |||
@@ -6728,7 +6728,9 @@ static int idle_balance(struct rq *this_rq) | |||
6728 | 6728 | ||
6729 | out: | 6729 | out: |
6730 | /* Is there a task of a high priority class? */ | 6730 | /* Is there a task of a high priority class? */ |
6731 | if (this_rq->nr_running != this_rq->cfs.h_nr_running) | 6731 | if (this_rq->nr_running != this_rq->cfs.h_nr_running && |
6732 | (this_rq->dl.dl_nr_running || | ||
6733 | (this_rq->rt.rt_nr_running && !rt_rq_throttled(&this_rq->rt)))) | ||
6732 | pulled_task = -1; | 6734 | pulled_task = -1; |
6733 | 6735 | ||
6734 | if (pulled_task) { | 6736 | if (pulled_task) { |
diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c index f3cee0a63b76..d8cdf1618551 100644 --- a/kernel/sched/rt.c +++ b/kernel/sched/rt.c | |||
@@ -470,11 +470,6 @@ static void sched_rt_rq_dequeue(struct rt_rq *rt_rq) | |||
470 | dequeue_rt_entity(rt_se); | 470 | dequeue_rt_entity(rt_se); |
471 | } | 471 | } |
472 | 472 | ||
473 | static inline int rt_rq_throttled(struct rt_rq *rt_rq) | ||
474 | { | ||
475 | return rt_rq->rt_throttled && !rt_rq->rt_nr_boosted; | ||
476 | } | ||
477 | |||
478 | static int rt_se_boosted(struct sched_rt_entity *rt_se) | 473 | static int rt_se_boosted(struct sched_rt_entity *rt_se) |
479 | { | 474 | { |
480 | struct rt_rq *rt_rq = group_rt_rq(rt_se); | 475 | struct rt_rq *rt_rq = group_rt_rq(rt_se); |
@@ -545,11 +540,6 @@ static inline void sched_rt_rq_dequeue(struct rt_rq *rt_rq) | |||
545 | { | 540 | { |
546 | } | 541 | } |
547 | 542 | ||
548 | static inline int rt_rq_throttled(struct rt_rq *rt_rq) | ||
549 | { | ||
550 | return rt_rq->rt_throttled; | ||
551 | } | ||
552 | |||
553 | static inline const struct cpumask *sched_rt_period_mask(void) | 543 | static inline const struct cpumask *sched_rt_period_mask(void) |
554 | { | 544 | { |
555 | return cpu_online_mask; | 545 | return cpu_online_mask; |
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index 378bff76267f..f2de7a175620 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h | |||
@@ -423,6 +423,18 @@ struct rt_rq { | |||
423 | #endif | 423 | #endif |
424 | }; | 424 | }; |
425 | 425 | ||
426 | #ifdef CONFIG_RT_GROUP_SCHED | ||
427 | static inline int rt_rq_throttled(struct rt_rq *rt_rq) | ||
428 | { | ||
429 | return rt_rq->rt_throttled && !rt_rq->rt_nr_boosted; | ||
430 | } | ||
431 | #else | ||
432 | static inline int rt_rq_throttled(struct rt_rq *rt_rq) | ||
433 | { | ||
434 | return rt_rq->rt_throttled; | ||
435 | } | ||
436 | #endif | ||
437 | |||
426 | /* Deadline class' related fields in a runqueue */ | 438 | /* Deadline class' related fields in a runqueue */ |
427 | struct dl_rq { | 439 | struct dl_rq { |
428 | /* runqueue is an rbtree, ordered by deadline */ | 440 | /* runqueue is an rbtree, ordered by deadline */ |