Commit 6667deb69ee3b8a31ea88e1303cf3ad7d4f221da
Committed by
Ralf Baechle
1 parent
ba9786f324
Exists in
master
and in
39 other branches
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); |