diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-05-21 14:52:00 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-05-21 14:52:00 -0400 |
commit | 970c305aa802346aaa741ab241f6f3f63d623cc0 (patch) | |
tree | 8e81fbe88704a2e20f93796b4ca52b1887e39dfb | |
parent | e7a3d62749183576854cdc961b8b1cddf1aed71e (diff) | |
parent | 8663effb24f9430394d3bf1ed2dac42a771421d1 (diff) |
Merge branch 'sched-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull scheduler fix from Thomas Gleixner:
"A single scheduler fix:
Prevent idle task from ever being preempted. That makes sure that
synchronize_rcu_tasks() which is ignoring idle task does not pretend
that no task is stuck in preempted state. If that happens and idle was
preempted on a ftrace trampoline the machine crashes due to
inconsistent state"
* 'sched-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
sched/core: Call __schedule() from do_idle() without enabling preemption
-rw-r--r-- | kernel/sched/core.c | 25 | ||||
-rw-r--r-- | kernel/sched/idle.c | 2 | ||||
-rw-r--r-- | kernel/sched/sched.h | 2 |
3 files changed, 28 insertions, 1 deletions
diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 759f4bd52cd6..803c3bc274c4 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c | |||
@@ -3502,6 +3502,31 @@ asmlinkage __visible void __sched schedule(void) | |||
3502 | } | 3502 | } |
3503 | EXPORT_SYMBOL(schedule); | 3503 | EXPORT_SYMBOL(schedule); |
3504 | 3504 | ||
3505 | /* | ||
3506 | * synchronize_rcu_tasks() makes sure that no task is stuck in preempted | ||
3507 | * state (have scheduled out non-voluntarily) by making sure that all | ||
3508 | * tasks have either left the run queue or have gone into user space. | ||
3509 | * As idle tasks do not do either, they must not ever be preempted | ||
3510 | * (schedule out non-voluntarily). | ||
3511 | * | ||
3512 | * schedule_idle() is similar to schedule_preempt_disable() except that it | ||
3513 | * never enables preemption because it does not call sched_submit_work(). | ||
3514 | */ | ||
3515 | void __sched schedule_idle(void) | ||
3516 | { | ||
3517 | /* | ||
3518 | * As this skips calling sched_submit_work(), which the idle task does | ||
3519 | * regardless because that function is a nop when the task is in a | ||
3520 | * TASK_RUNNING state, make sure this isn't used someplace that the | ||
3521 | * current task can be in any other state. Note, idle is always in the | ||
3522 | * TASK_RUNNING state. | ||
3523 | */ | ||
3524 | WARN_ON_ONCE(current->state); | ||
3525 | do { | ||
3526 | __schedule(false); | ||
3527 | } while (need_resched()); | ||
3528 | } | ||
3529 | |||
3505 | #ifdef CONFIG_CONTEXT_TRACKING | 3530 | #ifdef CONFIG_CONTEXT_TRACKING |
3506 | asmlinkage __visible void __sched schedule_user(void) | 3531 | asmlinkage __visible void __sched schedule_user(void) |
3507 | { | 3532 | { |
diff --git a/kernel/sched/idle.c b/kernel/sched/idle.c index 2a25a9ec2c6e..ef63adce0c9c 100644 --- a/kernel/sched/idle.c +++ b/kernel/sched/idle.c | |||
@@ -265,7 +265,7 @@ static void do_idle(void) | |||
265 | smp_mb__after_atomic(); | 265 | smp_mb__after_atomic(); |
266 | 266 | ||
267 | sched_ttwu_pending(); | 267 | sched_ttwu_pending(); |
268 | schedule_preempt_disabled(); | 268 | schedule_idle(); |
269 | 269 | ||
270 | if (unlikely(klp_patch_pending(current))) | 270 | if (unlikely(klp_patch_pending(current))) |
271 | klp_update_patch_state(current); | 271 | klp_update_patch_state(current); |
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index 7808ab050599..6dda2aab731e 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h | |||
@@ -1467,6 +1467,8 @@ static inline struct cpuidle_state *idle_get_state(struct rq *rq) | |||
1467 | } | 1467 | } |
1468 | #endif | 1468 | #endif |
1469 | 1469 | ||
1470 | extern void schedule_idle(void); | ||
1471 | |||
1470 | extern void sysrq_sched_debug_show(void); | 1472 | extern void sysrq_sched_debug_show(void); |
1471 | extern void sched_init_granularity(void); | 1473 | extern void sched_init_granularity(void); |
1472 | extern void update_max_interval(void); | 1474 | extern void update_max_interval(void); |