aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2017-05-21 14:52:00 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2017-05-21 14:52:00 -0400
commit970c305aa802346aaa741ab241f6f3f63d623cc0 (patch)
tree8e81fbe88704a2e20f93796b4ca52b1887e39dfb
parente7a3d62749183576854cdc961b8b1cddf1aed71e (diff)
parent8663effb24f9430394d3bf1ed2dac42a771421d1 (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.c25
-rw-r--r--kernel/sched/idle.c2
-rw-r--r--kernel/sched/sched.h2
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}
3503EXPORT_SYMBOL(schedule); 3503EXPORT_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 */
3515void __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
3506asmlinkage __visible void __sched schedule_user(void) 3531asmlinkage __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
1470extern void schedule_idle(void);
1471
1470extern void sysrq_sched_debug_show(void); 1472extern void sysrq_sched_debug_show(void);
1471extern void sched_init_granularity(void); 1473extern void sched_init_granularity(void);
1472extern void update_max_interval(void); 1474extern void update_max_interval(void);