From c5e062079a7090891ea5cd1b23a7eab52b156b2a Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 26 Jul 2002 01:28:07 -0700 Subject: [PATCH] Hot-plug CPU Boot Changes This patch alters the boot sequence to "plug in" each CPU, one at a time. You need the patch for each architecture, as well. The interface used to be "smp_boot_cpus()", "smp_commence()", and each arch implemented the "maxcpus" boot arg itself. With this patch, it is: smp_prepare_cpus(maxcpus): probe for cpus and set up cpu_possible(cpu). __cpu_up(cpu): called *after* initcalls, for each cpu where cpu_possible(cpu) is true. smp_cpus_done(maxcpus): called after every cpu has been brought up --- kernel/Makefile | 1 + kernel/cpu.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++ kernel/sched.c | 58 +++++++++++++++++++++++++++----------------------------- kernel/softirq.c | 37 ++++++++++++++++++++++++------------ 4 files changed, 108 insertions(+), 42 deletions(-) create mode 100644 kernel/cpu.c (limited to 'kernel') diff --git a/kernel/Makefile b/kernel/Makefile index d0cad7d5115c..4834fc454271 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -17,6 +17,7 @@ obj-y = sched.o dma.o fork.o exec_domain.o panic.o printk.o \ sysctl.o capability.o ptrace.o timer.o user.o \ signal.o sys.o kmod.o context.o futex.o platform.o +obj-$(CONFIG_SMP) += cpu.o obj-$(CONFIG_UID16) += uid16.o obj-$(CONFIG_MODULES) += ksyms.o obj-$(CONFIG_PM) += pm.o diff --git a/kernel/cpu.c b/kernel/cpu.c new file mode 100644 index 000000000000..b1820a5536d6 --- /dev/null +++ b/kernel/cpu.c @@ -0,0 +1,54 @@ +/* CPU control. + * (C) 2001 Rusty Russell + * This code is licenced under the GPL. + */ +#include +#include +#include +#include +#include +#include +#include + +/* This protects CPUs going up and down... */ +DECLARE_MUTEX(cpucontrol); + +static struct notifier_block *cpu_chain = NULL; + +/* Need to know about CPUs going up/down? */ +int register_cpu_notifier(struct notifier_block *nb) +{ + return notifier_chain_register(&cpu_chain, nb); +} + +void unregister_cpu_notifier(struct notifier_block *nb) +{ + notifier_chain_unregister(&cpu_chain,nb); +} + +int __devinit cpu_up(unsigned int cpu) +{ + int ret; + + if ((ret = down_interruptible(&cpucontrol)) != 0) + return ret; + + if (cpu_online(cpu)) { + ret = -EINVAL; + goto out; + } + + /* Arch-specific enabling code. */ + ret = __cpu_up(cpu); + if (ret != 0) goto out; + if (!cpu_online(cpu)) + BUG(); + + /* Now call notifier in preparation. */ + printk("CPU %u IS NOW UP!\n", cpu); + notifier_call_chain(&cpu_chain, CPU_ONLINE, (void *)cpu); + + out: + up(&cpucontrol); + return ret; +} diff --git a/kernel/sched.c b/kernel/sched.c index a54ee5a0356c..67ac32a24c1f 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -27,6 +27,8 @@ #include #include #include +#include +#include /* * Convert user-nice values [ -20 ... 0 ... 19 ] @@ -1777,9 +1779,11 @@ void set_cpus_allowed(task_t *p, unsigned long new_mask) migration_req_t req; runqueue_t *rq; +#if 0 /* FIXME: Grab cpu_lock, return error on this case. --RR */ new_mask &= cpu_online_map; if (!new_mask) BUG(); +#endif preempt_disable(); rq = task_rq_lock(p, &flags); @@ -1812,8 +1816,6 @@ out: preempt_enable(); } -static __initdata int master_migration_thread; - static int migration_thread(void * bind_cpu) { int cpu = (int) (long) bind_cpu; @@ -1825,15 +1827,7 @@ static int migration_thread(void * bind_cpu) sigfillset(¤t->blocked); set_fs(KERNEL_DS); - /* - * The first migration thread is started on the boot CPU, it - * migrates the other migration threads to their destination CPUs. - */ - if (cpu != master_migration_thread) { - while (!cpu_rq(master_migration_thread)->migration_thread) - yield(); - set_cpus_allowed(current, 1UL << cpu); - } + set_cpus_allowed(current, 1UL << cpu); printk("migration_task %d on cpu=%d\n", cpu, smp_processor_id()); ret = setscheduler(0, SCHED_FIFO, ¶m); @@ -1890,29 +1884,33 @@ repeat: } } -void __init migration_init(void) +static int migration_call(struct notifier_block *nfb, + unsigned long action, + void *hcpu) { - int cpu; - - master_migration_thread = smp_processor_id(); - current->cpus_allowed = 1UL << master_migration_thread; - - for (cpu = 0; cpu < NR_CPUS; cpu++) { - if (!cpu_online(cpu)) - continue; - if (kernel_thread(migration_thread, (void *) (long) cpu, - CLONE_FS | CLONE_FILES | CLONE_SIGNAL) < 0) - BUG(); + switch (action) { + case CPU_ONLINE: + printk("Starting migration thread for cpu %li\n", + (long)hcpu); + kernel_thread(migration_thread, hcpu, + CLONE_FS | CLONE_FILES | CLONE_SIGNAL); + break; } - current->cpus_allowed = -1L; + return NOTIFY_OK; +} - for (cpu = 0; cpu < NR_CPUS; cpu++) { - if (!cpu_online(cpu)) - continue; - while (!cpu_rq(cpu)->migration_thread) - schedule_timeout(2); - } +static struct notifier_block migration_notifier = { &migration_call, NULL, 0 }; + +int __init migration_init(void) +{ + /* Start one for boot CPU. */ + migration_call(&migration_notifier, CPU_ONLINE, + (void *)smp_processor_id()); + register_cpu_notifier(&migration_notifier); + return 0; } + +__initcall(migration_init); #endif extern void init_timervecs(void); diff --git a/kernel/softirq.c b/kernel/softirq.c index 135106c390c4..38ae82b344c0 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c @@ -17,6 +17,7 @@ #include #include #include +#include /* - No shared variables, all the data are CPU local. @@ -387,20 +388,32 @@ static int ksoftirqd(void * __bind_cpu) } } -static __init int spawn_ksoftirqd(void) +static int __devinit cpu_callback(struct notifier_block *nfb, + unsigned long action, + void *hcpu) { - int cpu; + int hotcpu = (unsigned long)hcpu; - for (cpu = 0; cpu < NR_CPUS; cpu++) { - if (!cpu_online(cpu)) - continue; - if (kernel_thread(ksoftirqd, (void *) (long) cpu, - CLONE_FS | CLONE_FILES | CLONE_SIGNAL) < 0) - printk("spawn_ksoftirqd() failed for cpu %d\n", cpu); - else - while (!ksoftirqd_task(cpu)) - yield(); - } + if (action == CPU_ONLINE) { + if (kernel_thread(ksoftirqd, hcpu, + CLONE_FS | CLONE_FILES | CLONE_SIGNAL) < 0) { + printk("ksoftirqd for %i failed\n", hotcpu); + return NOTIFY_BAD; + } + + while (!ksoftirqd_task(hotcpu)) + yield(); + return NOTIFY_OK; + } + return NOTIFY_BAD; +} + +static struct notifier_block cpu_nfb = { &cpu_callback, NULL, 0 }; + +static __init int spawn_ksoftirqd(void) +{ + cpu_callback(&cpu_nfb, CPU_ONLINE, (void *)smp_processor_id()); + register_cpu_notifier(&cpu_nfb); return 0; } -- cgit v1.2.3