Commit 6667deb69ee3b8a31ea88e1303cf3ad7d4f221da

Authored by Maksim Rayskiy
Committed by Ralf Baechle
1 parent ba9786f324

MIPS: Move idle task creation to work queue

To avoid forking usermode thread when creating an idle task, move fork_idle
to a work queue.

If kernel starts with maxcpus= option which does not bring all available
cpus online at boot time, idle tasks for offline cpus are not created. If
later offline cpus are hotplugged through sysfs, __cpu_up is called in
the context of the user task, and fork_idle copies its non-zero mm
pointer.  This causes BUG() in per_cpu_trap_init.

This also avoids issues with resource limits of the CPU writing to sysfs,
containers, maybe others.

Signed-off-by: Maksim Rayskiy <mrayskiy@broadcom.com>
To: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/2070/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>

Showing 1 changed file with 29 additions and 2 deletions Side-by-side Diff

arch/mips/kernel/smp.c
... ... @@ -193,6 +193,22 @@
193 193 */
194 194 static struct task_struct *cpu_idle_thread[NR_CPUS];
195 195  
  196 +struct create_idle {
  197 + struct work_struct work;
  198 + struct task_struct *idle;
  199 + struct completion done;
  200 + int cpu;
  201 +};
  202 +
  203 +static void __cpuinit do_fork_idle(struct work_struct *work)
  204 +{
  205 + struct create_idle *c_idle =
  206 + container_of(work, struct create_idle, work);
  207 +
  208 + c_idle->idle = fork_idle(c_idle->cpu);
  209 + complete(&c_idle->done);
  210 +}
  211 +
196 212 int __cpuinit __cpu_up(unsigned int cpu)
197 213 {
198 214 struct task_struct *idle;
... ... @@ -203,8 +219,19 @@
203 219 * Linux can schedule processes on this slave.
204 220 */
205 221 if (!cpu_idle_thread[cpu]) {
206   - idle = fork_idle(cpu);
207   - cpu_idle_thread[cpu] = idle;
  222 + /*
  223 + * Schedule work item to avoid forking user task
  224 + * Ported from arch/x86/kernel/smpboot.c
  225 + */
  226 + struct create_idle c_idle = {
  227 + .cpu = cpu,
  228 + .done = COMPLETION_INITIALIZER_ONSTACK(c_idle.done),
  229 + };
  230 +
  231 + INIT_WORK_ONSTACK(&c_idle.work, do_fork_idle);
  232 + schedule_work(&c_idle.work);
  233 + wait_for_completion(&c_idle.done);
  234 + idle = cpu_idle_thread[cpu] = c_idle.idle;
208 235  
209 236 if (IS_ERR(idle))
210 237 panic(KERN_ERR "Fork failed for CPU %d", cpu);