sched: Cleanup cpu_active madness
author黄涛 <huangtao@rock-chips.com>
Thu, 12 Jul 2012 01:46:55 +0000 (09:46 +0800)
committer黄涛 <huangtao@rock-chips.com>
Thu, 12 Jul 2012 01:49:51 +0000 (09:49 +0800)
commit 5fbd036b552f633abb394a319f7c62a5c86a9cd7 upstream.

Stepan found:

CPU0 CPUn

_cpu_up()
  __cpu_up()

boostrap()
  notify_cpu_starting()
  set_cpu_online()
  while (!cpu_active())
    cpu_relax()

<PREEMPT-out>

smp_call_function(.wait=1)
  /* we find cpu_online() is true */
  arch_send_call_function_ipi_mask()

  /* wait-forever-more */

<PREEMPT-in>
  local_irq_enable()

  cpu_notify(CPU_ONLINE)
    sched_cpu_active()
      set_cpu_active()

Now the purpose of cpu_active is mostly with bringing down a cpu, where
we mark it !active to avoid the load-balancer from moving tasks to it
while we tear down the cpu. This is required because we only update the
sched_domain tree after we brought the cpu-down. And this is needed so
that some tasks can still run while we bring it down, we just don't want
new tasks to appear.

On cpu-up however the sched_domain tree doesn't yet include the new cpu,
so its invisible to the load-balancer, regardless of the active state.
So instead of setting the active state after we boot the new cpu (and
consequently having to wait for it before enabling interrupts) set the
cpu active before we set it online and avoid the whole mess.

arch/arm/kernel/smp.c
kernel/sched.c

index 2d9fb0a794c06f7a512a3c459e16ce38dc67f796..a45d38dcac09903ff11f0bbdf6850347addb8a6c 100644 (file)
@@ -322,13 +322,6 @@ asmlinkage void __cpuinit secondary_start_kernel(void)
         */
        percpu_timer_setup();
 
-       while (!cpu_active(cpu))
-               cpu_relax();
-
-       /*
-        * cpu_active bit is set, so it's safe to enable interrupts
-        * now.
-        */
        local_irq_enable();
        local_fiq_enable();
 
index 0f81bd408b29244f00d7ae7ce00068a57a2eb359..62948763bc8b8417165870bdb3ca7b6665a0b3ce 100644 (file)
@@ -6481,7 +6481,7 @@ static int __cpuinit sched_cpu_active(struct notifier_block *nfb,
                                      unsigned long action, void *hcpu)
 {
        switch (action & ~CPU_TASKS_FROZEN) {
-       case CPU_ONLINE:
+       case CPU_STARTING:
        case CPU_DOWN_FAILED:
                set_cpu_active((long)hcpu, true);
                return NOTIFY_OK;