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
Unified · Split
| @@ -3502,6 +3502,31 @@ asmlinkage __visible void __sched schedule(void) · 3501 unmodified lines | |||
| 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 | { |
| @@ -265,7 +265,7 @@ static void do_idle(void) · 264 unmodified lines | |||
| 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); |
| @@ -1467,6 +1467,8 @@ static inline struct cpuidle_state *idle_get_state(struct rq *rq) · 1466 unmodified lines | |||
| 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); |