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 | 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 | 3530 | #ifdef CONFIG_CONTEXT_TRACKING |
| 3506 | 3531 | asmlinkage __visible void __sched schedule_user(void) |
| 3507 | 3532 | { |
| @@ -265,7 +265,7 @@ static void do_idle(void) · 264 unmodified lines | ||
| 265 | 265 | smp_mb__after_atomic(); |
| 266 | 266 | |
| 267 | 267 | sched_ttwu_pending(); |
| 268 | − schedule_preempt_disabled(); | |
| 268 | + schedule_idle(); | |
| 269 | 269 | |
| 270 | 270 | if (unlikely(klp_patch_pending(current))) |
| 271 | 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 | 1468 | #endif |
| 1469 | 1469 | |
| 1470 | +extern void schedule_idle(void); | |
| 1471 | + | |
| 1470 | 1472 | extern void sysrq_sched_debug_show(void); |
| 1471 | 1473 | extern void sched_init_granularity(void); |
| 1472 | 1474 | extern void update_max_interval(void); |