aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Zijlstra <peterz@infradead.org>2015-08-13 17:09:29 -0400
committerIngo Molnar <mingo@kernel.org>2015-09-18 03:17:50 -0400
commitde9b8f5dcbd94bfb1d249907a635f1fb1968e19c (patch)
tree82744e9ef61c2cd985c7f9af1f6af287255464ac
parenta7d5c189719846889c029c34e24e166a465368fa (diff)
sched: Fix crash trying to dequeue/enqueue the idle thread
Sasha reports that his virtual machine tries to schedule the idle thread since commit 6c37067e2786 ("sched: Change the sched_class::set_cpus_allowed() calling context"). Hit trace shows this happening from idle_thread_get()->init_idle(), which is the _second_ init_idle() invocation on that task_struct, the first being done through idle_init()->fork_idle(). (this code is insane...) Because we call init_idle() twice in a row, its ->sched_class == &idle_sched_class and ->on_rq = TASK_ON_RQ_QUEUED. This means do_set_cpus_allowed() think we're queued and will call dequeue_task(), which is implemented with BUG() for the idle class, seeing how dequeueing the idle task is a daft thing. Aside of the whole insanity of calling init_idle() _twice_, change the code to call set_cpus_allowed_common() instead as this is 'obviously' before the idle task gets ran etc.. Reported-by: Sasha Levin <sasha.levin@oracle.com> Tested-by: Sasha Levin <sasha.levin@oracle.com> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Fixes: 6c37067e2786 ("sched: Change the sched_class::set_cpus_allowed() calling context") Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--kernel/sched/core.c14
1 files changed, 11 insertions, 3 deletions
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 97d276ff1edb..f0d043ec0182 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -4927,7 +4927,15 @@ void init_idle(struct task_struct *idle, int cpu)
4927 idle->state = TASK_RUNNING; 4927 idle->state = TASK_RUNNING;
4928 idle->se.exec_start = sched_clock(); 4928 idle->se.exec_start = sched_clock();
4929 4929
4930 do_set_cpus_allowed(idle, cpumask_of(cpu)); 4930#ifdef CONFIG_SMP
4931 /*
4932 * Its possible that init_idle() gets called multiple times on a task,
4933 * in that case do_set_cpus_allowed() will not do the right thing.
4934 *
4935 * And since this is boot we can forgo the serialization.
4936 */
4937 set_cpus_allowed_common(idle, cpumask_of(cpu));
4938#endif
4931 /* 4939 /*
4932 * We're having a chicken and egg problem, even though we are 4940 * We're having a chicken and egg problem, even though we are
4933 * holding rq->lock, the cpu isn't yet set to this cpu so the 4941 * holding rq->lock, the cpu isn't yet set to this cpu so the
@@ -4944,7 +4952,7 @@ void init_idle(struct task_struct *idle, int cpu)
4944 4952
4945 rq->curr = rq->idle = idle; 4953 rq->curr = rq->idle = idle;
4946 idle->on_rq = TASK_ON_RQ_QUEUED; 4954 idle->on_rq = TASK_ON_RQ_QUEUED;
4947#if defined(CONFIG_SMP) 4955#ifdef CONFIG_SMP
4948 idle->on_cpu = 1; 4956 idle->on_cpu = 1;
4949#endif 4957#endif
4950 raw_spin_unlock(&rq->lock); 4958 raw_spin_unlock(&rq->lock);
@@ -4959,7 +4967,7 @@ void init_idle(struct task_struct *idle, int cpu)
4959 idle->sched_class = &idle_sched_class; 4967 idle->sched_class = &idle_sched_class;
4960 ftrace_graph_init_idle_task(idle, cpu); 4968 ftrace_graph_init_idle_task(idle, cpu);
4961 vtime_init_idle(idle, cpu); 4969 vtime_init_idle(idle, cpu);
4962#if defined(CONFIG_SMP) 4970#ifdef CONFIG_SMP
4963 sprintf(idle->comm, "%s/%d", INIT_TASK_COMM, cpu); 4971 sprintf(idle->comm, "%s/%d", INIT_TASK_COMM, cpu);
4964#endif 4972#endif
4965} 4973}