From: Rusty Russell The cpu hotplug code actually provides two notifiers: CPU_UP_PREPARE which preceeds the online and can fail, and CPU_ONLINE which can't. Current usage is only done at boot, so this distinction doesn't matter, but it's a bad example to set. This also means that the migration threads do not have to be higher priority than the others, since they are ready to go before any CPU_ONLINE callbacks are done. This patch is experimental but fairly straight foward: I haven't been able to test it since extracting it from the hotplug cpu code, so it's possible I screwed something up. --- kernel/sched.c | 23 +++++++++++++++-------- kernel/softirq.c | 15 ++++++++++++--- 2 files changed, 27 insertions(+), 11 deletions(-) diff -puN kernel/sched.c~use-CPU_UP_PREPARE-properly kernel/sched.c --- 25/kernel/sched.c~use-CPU_UP_PREPARE-properly 2004-02-06 18:52:40.000000000 -0800 +++ 25-akpm/kernel/sched.c 2004-02-06 18:52:40.000000000 -0800 @@ -3134,29 +3134,36 @@ static int migration_call(struct notifie struct task_struct *p; switch (action) { - case CPU_ONLINE: + case CPU_UP_PREPARE: p = kthread_create(migration_thread, hcpu, "migration/%d",cpu); if (IS_ERR(p)) return NOTIFY_BAD; kthread_bind(p, cpu); cpu_rq(cpu)->migration_thread = p; - wake_up_process(p); + break; + case CPU_ONLINE: + /* Strictly unneccessary, as first user will wake it. */ + wake_up_process(cpu_rq(cpu)->migration_thread); break; } return NOTIFY_OK; } -/* Want this before the other threads, so they can use set_cpus_allowed. */ -static struct notifier_block migration_notifier = { - .notifier_call = &migration_call, - .priority = 10, +/* + * We want this after the other threads, so they can use set_cpus_allowed + * from their CPU_OFFLINE callback + */ +static struct notifier_block __devinitdata migration_notifier = { + .notifier_call = migration_call, + .priority = -10, }; int __init migration_init(void) { + void *cpu = (void *)(long)smp_processor_id(); /* Start one for boot CPU. */ - migration_call(&migration_notifier, CPU_ONLINE, - (void *)(long)smp_processor_id()); + migration_call(&migration_notifier, CPU_UP_PREPARE, cpu); + migration_call(&migration_notifier, CPU_ONLINE, cpu); register_cpu_notifier(&migration_notifier); return 0; } diff -puN kernel/softirq.c~use-CPU_UP_PREPARE-properly kernel/softirq.c --- 25/kernel/softirq.c~use-CPU_UP_PREPARE-properly 2004-02-06 18:52:40.000000000 -0800 +++ 25-akpm/kernel/softirq.c 2004-02-06 18:52:40.000000000 -0800 @@ -351,7 +351,10 @@ static int __devinit cpu_callback(struct int hotcpu = (unsigned long)hcpu; struct task_struct *p; - if (action == CPU_ONLINE) { + switch (action) { + case CPU_UP_PREPARE: + BUG_ON(per_cpu(tasklet_vec, hotcpu).list); + BUG_ON(per_cpu(tasklet_hi_vec, hotcpu).list); p = kthread_create(ksoftirqd, hcpu, "ksoftirqd/%d", hotcpu); if (IS_ERR(p)) { printk("ksoftirqd for %i failed\n", hotcpu); @@ -359,7 +362,11 @@ static int __devinit cpu_callback(struct } per_cpu(ksoftirqd, hotcpu) = p; kthread_bind(p, hotcpu); - wake_up_process(p); + per_cpu(ksoftirqd, hotcpu) = p; + break; + case CPU_ONLINE: + wake_up_process(per_cpu(ksoftirqd, hotcpu)); + break; } return NOTIFY_OK; } @@ -370,7 +377,9 @@ static struct notifier_block __devinitda __init int spawn_ksoftirqd(void) { - cpu_callback(&cpu_nfb, CPU_ONLINE, (void *)(long)smp_processor_id()); + void *cpu = (void *)(long)smp_processor_id(); + cpu_callback(&cpu_nfb, CPU_UP_PREPARE, cpu); + cpu_callback(&cpu_nfb, CPU_ONLINE, cpu); register_cpu_notifier(&cpu_nfb); return 0; } _