]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Merge branch 'sched-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
authorLinus Torvalds <torvalds@linux-foundation.org>
Sun, 21 May 2017 18:52:00 +0000 (11:52 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sun, 21 May 2017 18:52:00 +0000 (11:52 -0700)
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

kernel/sched/core.c
kernel/sched/idle.c
kernel/sched/sched.h

index 759f4bd52cd6b3724b858d41f57ff305a3747c8b..803c3bc274c4660bb672c2522331db967883aee4 100644 (file)
@@ -3502,6 +3502,31 @@ asmlinkage __visible void __sched schedule(void)
 }
 EXPORT_SYMBOL(schedule);
 
+/*
+ * synchronize_rcu_tasks() makes sure that no task is stuck in preempted
+ * state (have scheduled out non-voluntarily) by making sure that all
+ * tasks have either left the run queue or have gone into user space.
+ * As idle tasks do not do either, they must not ever be preempted
+ * (schedule out non-voluntarily).
+ *
+ * schedule_idle() is similar to schedule_preempt_disable() except that it
+ * never enables preemption because it does not call sched_submit_work().
+ */
+void __sched schedule_idle(void)
+{
+       /*
+        * As this skips calling sched_submit_work(), which the idle task does
+        * regardless because that function is a nop when the task is in a
+        * TASK_RUNNING state, make sure this isn't used someplace that the
+        * current task can be in any other state. Note, idle is always in the
+        * TASK_RUNNING state.
+        */
+       WARN_ON_ONCE(current->state);
+       do {
+               __schedule(false);
+       } while (need_resched());
+}
+
 #ifdef CONFIG_CONTEXT_TRACKING
 asmlinkage __visible void __sched schedule_user(void)
 {
index 2a25a9ec2c6e5806ad8528717c5b372d750dcf9e..ef63adce0c9cf98eecd9a6896e16d804c6bc1759 100644 (file)
@@ -265,7 +265,7 @@ static void do_idle(void)
        smp_mb__after_atomic();
 
        sched_ttwu_pending();
-       schedule_preempt_disabled();
+       schedule_idle();
 
        if (unlikely(klp_patch_pending(current)))
                klp_update_patch_state(current);
index 7808ab05059991a2dad05bf073f1fee539f0fbbd..6dda2aab731e04c5e1f88272f180f44df22e907a 100644 (file)
@@ -1467,6 +1467,8 @@ static inline struct cpuidle_state *idle_get_state(struct rq *rq)
 }
 #endif
 
+extern void schedule_idle(void);
+
 extern void sysrq_sched_debug_show(void);
 extern void sched_init_granularity(void);
 extern void update_max_interval(void);