aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-05-21 22:43:57 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-05-21 22:43:57 -0400
commitbf67f3a5c456a18f2e8d062f7e88506ef2cd9837 (patch)
tree2a2324b2572162059307db82f9238eeb25673a77 /kernel
parent226da0dbc84ed97f448523e2a4cb91c27fa68ed9 (diff)
parent203dacbdca977bedaba61ad2fca75d934060a5d5 (diff)
Merge branch 'smp-hotplug-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull smp hotplug cleanups from Thomas Gleixner: "This series is merily a cleanup of code copied around in arch/* and not changing any of the real cpu hotplug horrors yet. I wish I'd had something more substantial for 3.5, but I underestimated the lurking horror..." Fix up trivial conflicts in arch/{arm,sparc,x86}/Kconfig and arch/sparc/include/asm/thread_info_32.h * 'smp-hotplug-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (79 commits) um: Remove leftover declaration of alloc_task_struct_node() task_allocator: Use config switches instead of magic defines sparc: Use common threadinfo allocator score: Use common threadinfo allocator sh-use-common-threadinfo-allocator mn10300: Use common threadinfo allocator powerpc: Use common threadinfo allocator mips: Use common threadinfo allocator hexagon: Use common threadinfo allocator m32r: Use common threadinfo allocator frv: Use common threadinfo allocator cris: Use common threadinfo allocator x86: Use common threadinfo allocator c6x: Use common threadinfo allocator fork: Provide kmemcache based thread_info allocator tile: Use common threadinfo allocator fork: Provide weak arch_release_[task_struct|thread_info] functions fork: Move thread info gfp flags to header fork: Remove the weak insanity sh: Remove cpu_idle_wait() ...
Diffstat (limited to 'kernel')
-rw-r--r--kernel/Makefile1
-rw-r--r--kernel/cpu.c13
-rw-r--r--kernel/fork.c69
-rw-r--r--kernel/sched/Makefile2
-rw-r--r--kernel/sched/core.c2
-rw-r--r--kernel/smp.c27
-rw-r--r--kernel/smpboot.c62
-rw-r--r--kernel/smpboot.h18
8 files changed, 171 insertions, 23 deletions
diff --git a/kernel/Makefile b/kernel/Makefile
index cb41b9547c9f..6c07f30fa9b7 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -43,6 +43,7 @@ obj-$(CONFIG_DEBUG_RT_MUTEXES) += rtmutex-debug.o
43obj-$(CONFIG_RT_MUTEX_TESTER) += rtmutex-tester.o 43obj-$(CONFIG_RT_MUTEX_TESTER) += rtmutex-tester.o
44obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o 44obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o
45obj-$(CONFIG_SMP) += smp.o 45obj-$(CONFIG_SMP) += smp.o
46obj-$(CONFIG_SMP) += smpboot.o
46ifneq ($(CONFIG_SMP),y) 47ifneq ($(CONFIG_SMP),y)
47obj-y += up.o 48obj-y += up.o
48endif 49endif
diff --git a/kernel/cpu.c b/kernel/cpu.c
index 2060c6e57027..0e6353cf147a 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -17,6 +17,8 @@
17#include <linux/gfp.h> 17#include <linux/gfp.h>
18#include <linux/suspend.h> 18#include <linux/suspend.h>
19 19
20#include "smpboot.h"
21
20#ifdef CONFIG_SMP 22#ifdef CONFIG_SMP
21/* Serializes the updates to cpu_online_mask, cpu_present_mask */ 23/* Serializes the updates to cpu_online_mask, cpu_present_mask */
22static DEFINE_MUTEX(cpu_add_remove_lock); 24static DEFINE_MUTEX(cpu_add_remove_lock);
@@ -295,11 +297,19 @@ static int __cpuinit _cpu_up(unsigned int cpu, int tasks_frozen)
295 int ret, nr_calls = 0; 297 int ret, nr_calls = 0;
296 void *hcpu = (void *)(long)cpu; 298 void *hcpu = (void *)(long)cpu;
297 unsigned long mod = tasks_frozen ? CPU_TASKS_FROZEN : 0; 299 unsigned long mod = tasks_frozen ? CPU_TASKS_FROZEN : 0;
300 struct task_struct *idle;
298 301
299 if (cpu_online(cpu) || !cpu_present(cpu)) 302 if (cpu_online(cpu) || !cpu_present(cpu))
300 return -EINVAL; 303 return -EINVAL;
301 304
302 cpu_hotplug_begin(); 305 cpu_hotplug_begin();
306
307 idle = idle_thread_get(cpu);
308 if (IS_ERR(idle)) {
309 ret = PTR_ERR(idle);
310 goto out;
311 }
312
303 ret = __cpu_notify(CPU_UP_PREPARE | mod, hcpu, -1, &nr_calls); 313 ret = __cpu_notify(CPU_UP_PREPARE | mod, hcpu, -1, &nr_calls);
304 if (ret) { 314 if (ret) {
305 nr_calls--; 315 nr_calls--;
@@ -309,7 +319,7 @@ static int __cpuinit _cpu_up(unsigned int cpu, int tasks_frozen)
309 } 319 }
310 320
311 /* Arch-specific enabling code. */ 321 /* Arch-specific enabling code. */
312 ret = __cpu_up(cpu); 322 ret = __cpu_up(cpu, idle);
313 if (ret != 0) 323 if (ret != 0)
314 goto out_notify; 324 goto out_notify;
315 BUG_ON(!cpu_online(cpu)); 325 BUG_ON(!cpu_online(cpu));
@@ -320,6 +330,7 @@ static int __cpuinit _cpu_up(unsigned int cpu, int tasks_frozen)
320out_notify: 330out_notify:
321 if (ret != 0) 331 if (ret != 0)
322 __cpu_notify(CPU_UP_CANCELED | mod, hcpu, nr_calls, NULL); 332 __cpu_notify(CPU_UP_CANCELED | mod, hcpu, nr_calls, NULL);
333out:
323 cpu_hotplug_done(); 334 cpu_hotplug_done();
324 335
325 return ret; 336 return ret;
diff --git a/kernel/fork.c b/kernel/fork.c
index 687a15d56243..9f9b296fa6df 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -112,32 +112,67 @@ int nr_processes(void)
112 return total; 112 return total;
113} 113}
114 114
115#ifndef __HAVE_ARCH_TASK_STRUCT_ALLOCATOR 115#ifndef CONFIG_ARCH_TASK_STRUCT_ALLOCATOR
116# define alloc_task_struct_node(node) \
117 kmem_cache_alloc_node(task_struct_cachep, GFP_KERNEL, node)
118# define free_task_struct(tsk) \
119 kmem_cache_free(task_struct_cachep, (tsk))
120static struct kmem_cache *task_struct_cachep; 116static struct kmem_cache *task_struct_cachep;
117
118static inline struct task_struct *alloc_task_struct_node(int node)
119{
120 return kmem_cache_alloc_node(task_struct_cachep, GFP_KERNEL, node);
121}
122
123void __weak arch_release_task_struct(struct task_struct *tsk) { }
124
125static inline void free_task_struct(struct task_struct *tsk)
126{
127 arch_release_task_struct(tsk);
128 kmem_cache_free(task_struct_cachep, tsk);
129}
121#endif 130#endif
122 131
123#ifndef __HAVE_ARCH_THREAD_INFO_ALLOCATOR 132#ifndef CONFIG_ARCH_THREAD_INFO_ALLOCATOR
133void __weak arch_release_thread_info(struct thread_info *ti) { }
134
135/*
136 * Allocate pages if THREAD_SIZE is >= PAGE_SIZE, otherwise use a
137 * kmemcache based allocator.
138 */
139# if THREAD_SIZE >= PAGE_SIZE
124static struct thread_info *alloc_thread_info_node(struct task_struct *tsk, 140static struct thread_info *alloc_thread_info_node(struct task_struct *tsk,
125 int node) 141 int node)
126{ 142{
127#ifdef CONFIG_DEBUG_STACK_USAGE 143 struct page *page = alloc_pages_node(node, THREADINFO_GFP,
128 gfp_t mask = GFP_KERNEL | __GFP_ZERO; 144 THREAD_SIZE_ORDER);
129#else
130 gfp_t mask = GFP_KERNEL;
131#endif
132 struct page *page = alloc_pages_node(node, mask, THREAD_SIZE_ORDER);
133 145
134 return page ? page_address(page) : NULL; 146 return page ? page_address(page) : NULL;
135} 147}
136 148
137static inline void free_thread_info(struct thread_info *ti) 149static inline void free_thread_info(struct thread_info *ti)
138{ 150{
151 arch_release_thread_info(ti);
139 free_pages((unsigned long)ti, THREAD_SIZE_ORDER); 152 free_pages((unsigned long)ti, THREAD_SIZE_ORDER);
140} 153}
154# else
155static struct kmem_cache *thread_info_cache;
156
157static struct thread_info *alloc_thread_info_node(struct task_struct *tsk,
158 int node)
159{
160 return kmem_cache_alloc_node(thread_info_cache, THREADINFO_GFP, node);
161}
162
163static void free_thread_info(struct thread_info *ti)
164{
165 arch_release_thread_info(ti);
166 kmem_cache_free(thread_info_cache, ti);
167}
168
169void thread_info_cache_init(void)
170{
171 thread_info_cache = kmem_cache_create("thread_info", THREAD_SIZE,
172 THREAD_SIZE, 0, NULL);
173 BUG_ON(thread_info_cache == NULL);
174}
175# endif
141#endif 176#endif
142 177
143/* SLAB cache for signal_struct structures (tsk->signal) */ 178/* SLAB cache for signal_struct structures (tsk->signal) */
@@ -204,17 +239,11 @@ void __put_task_struct(struct task_struct *tsk)
204} 239}
205EXPORT_SYMBOL_GPL(__put_task_struct); 240EXPORT_SYMBOL_GPL(__put_task_struct);
206 241
207/* 242void __init __weak arch_task_cache_init(void) { }
208 * macro override instead of weak attribute alias, to workaround
209 * gcc 4.1.0 and 4.1.1 bugs with weak attribute and empty functions.
210 */
211#ifndef arch_task_cache_init
212#define arch_task_cache_init()
213#endif
214 243
215void __init fork_init(unsigned long mempages) 244void __init fork_init(unsigned long mempages)
216{ 245{
217#ifndef __HAVE_ARCH_TASK_STRUCT_ALLOCATOR 246#ifndef CONFIG_ARCH_TASK_STRUCT_ALLOCATOR
218#ifndef ARCH_MIN_TASKALIGN 247#ifndef ARCH_MIN_TASKALIGN
219#define ARCH_MIN_TASKALIGN L1_CACHE_BYTES 248#define ARCH_MIN_TASKALIGN L1_CACHE_BYTES
220#endif 249#endif
diff --git a/kernel/sched/Makefile b/kernel/sched/Makefile
index 9a7dd35102a3..173ea52f3af0 100644
--- a/kernel/sched/Makefile
+++ b/kernel/sched/Makefile
@@ -16,5 +16,3 @@ obj-$(CONFIG_SMP) += cpupri.o
16obj-$(CONFIG_SCHED_AUTOGROUP) += auto_group.o 16obj-$(CONFIG_SCHED_AUTOGROUP) += auto_group.o
17obj-$(CONFIG_SCHEDSTATS) += stats.o 17obj-$(CONFIG_SCHEDSTATS) += stats.o
18obj-$(CONFIG_SCHED_DEBUG) += debug.o 18obj-$(CONFIG_SCHED_DEBUG) += debug.o
19
20
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index eb4131b8ad60..ea8a4769fea5 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -83,6 +83,7 @@
83 83
84#include "sched.h" 84#include "sched.h"
85#include "../workqueue_sched.h" 85#include "../workqueue_sched.h"
86#include "../smpboot.h"
86 87
87#define CREATE_TRACE_POINTS 88#define CREATE_TRACE_POINTS
88#include <trace/events/sched.h> 89#include <trace/events/sched.h>
@@ -7062,6 +7063,7 @@ void __init sched_init(void)
7062 /* May be allocated at isolcpus cmdline parse time */ 7063 /* May be allocated at isolcpus cmdline parse time */
7063 if (cpu_isolated_map == NULL) 7064 if (cpu_isolated_map == NULL)
7064 zalloc_cpumask_var(&cpu_isolated_map, GFP_NOWAIT); 7065 zalloc_cpumask_var(&cpu_isolated_map, GFP_NOWAIT);
7066 idle_thread_set_boot_cpu();
7065#endif 7067#endif
7066 init_sched_fair_class(); 7068 init_sched_fair_class();
7067 7069
diff --git a/kernel/smp.c b/kernel/smp.c
index 2f8b10ecf759..d0ae5b24875e 100644
--- a/kernel/smp.c
+++ b/kernel/smp.c
@@ -13,6 +13,8 @@
13#include <linux/smp.h> 13#include <linux/smp.h>
14#include <linux/cpu.h> 14#include <linux/cpu.h>
15 15
16#include "smpboot.h"
17
16#ifdef CONFIG_USE_GENERIC_SMP_HELPERS 18#ifdef CONFIG_USE_GENERIC_SMP_HELPERS
17static struct { 19static struct {
18 struct list_head queue; 20 struct list_head queue;
@@ -669,6 +671,8 @@ void __init smp_init(void)
669{ 671{
670 unsigned int cpu; 672 unsigned int cpu;
671 673
674 idle_threads_init();
675
672 /* FIXME: This should be done in userspace --RR */ 676 /* FIXME: This should be done in userspace --RR */
673 for_each_present_cpu(cpu) { 677 for_each_present_cpu(cpu) {
674 if (num_online_cpus() >= setup_max_cpus) 678 if (num_online_cpus() >= setup_max_cpus)
@@ -791,3 +795,26 @@ void on_each_cpu_cond(bool (*cond_func)(int cpu, void *info),
791 } 795 }
792} 796}
793EXPORT_SYMBOL(on_each_cpu_cond); 797EXPORT_SYMBOL(on_each_cpu_cond);
798
799static void do_nothing(void *unused)
800{
801}
802
803/**
804 * kick_all_cpus_sync - Force all cpus out of idle
805 *
806 * Used to synchronize the update of pm_idle function pointer. It's
807 * called after the pointer is updated and returns after the dummy
808 * callback function has been executed on all cpus. The execution of
809 * the function can only happen on the remote cpus after they have
810 * left the idle function which had been called via pm_idle function
811 * pointer. So it's guaranteed that nothing uses the previous pointer
812 * anymore.
813 */
814void kick_all_cpus_sync(void)
815{
816 /* Make sure the change is visible before we kick the cpus */
817 smp_mb();
818 smp_call_function(do_nothing, NULL, 1);
819}
820EXPORT_SYMBOL_GPL(kick_all_cpus_sync);
diff --git a/kernel/smpboot.c b/kernel/smpboot.c
new file mode 100644
index 000000000000..e1a797e028a3
--- /dev/null
+++ b/kernel/smpboot.c
@@ -0,0 +1,62 @@
1/*
2 * Common SMP CPU bringup/teardown functions
3 */
4#include <linux/err.h>
5#include <linux/smp.h>
6#include <linux/init.h>
7#include <linux/sched.h>
8#include <linux/percpu.h>
9
10#include "smpboot.h"
11
12#ifdef CONFIG_GENERIC_SMP_IDLE_THREAD
13/*
14 * For the hotplug case we keep the task structs around and reuse
15 * them.
16 */
17static DEFINE_PER_CPU(struct task_struct *, idle_threads);
18
19struct task_struct * __cpuinit idle_thread_get(unsigned int cpu)
20{
21 struct task_struct *tsk = per_cpu(idle_threads, cpu);
22
23 if (!tsk)
24 return ERR_PTR(-ENOMEM);
25 init_idle(tsk, cpu);
26 return tsk;
27}
28
29void __init idle_thread_set_boot_cpu(void)
30{
31 per_cpu(idle_threads, smp_processor_id()) = current;
32}
33
34static inline void idle_init(unsigned int cpu)
35{
36 struct task_struct *tsk = per_cpu(idle_threads, cpu);
37
38 if (!tsk) {
39 tsk = fork_idle(cpu);
40 if (IS_ERR(tsk))
41 pr_err("SMP: fork_idle() failed for CPU %u\n", cpu);
42 else
43 per_cpu(idle_threads, cpu) = tsk;
44 }
45}
46
47/**
48 * idle_thread_init - Initialize the idle thread for a cpu
49 * @cpu: The cpu for which the idle thread should be initialized
50 *
51 * Creates the thread if it does not exist.
52 */
53void __init idle_threads_init(void)
54{
55 unsigned int cpu;
56
57 for_each_possible_cpu(cpu) {
58 if (cpu != smp_processor_id())
59 idle_init(cpu);
60 }
61}
62#endif
diff --git a/kernel/smpboot.h b/kernel/smpboot.h
new file mode 100644
index 000000000000..80c0acfb8472
--- /dev/null
+++ b/kernel/smpboot.h
@@ -0,0 +1,18 @@
1#ifndef SMPBOOT_H
2#define SMPBOOT_H
3
4struct task_struct;
5
6int smpboot_prepare(unsigned int cpu);
7
8#ifdef CONFIG_GENERIC_SMP_IDLE_THREAD
9struct task_struct *idle_thread_get(unsigned int cpu);
10void idle_thread_set_boot_cpu(void);
11void idle_threads_init(void);
12#else
13static inline struct task_struct *idle_thread_get(unsigned int cpu) { return NULL; }
14static inline void idle_thread_set_boot_cpu(void) { }
15static inline void idle_threads_init(void) { }
16#endif
17
18#endif