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); |
