diff options
Diffstat (limited to 'arch/x86_64/kernel/vsyscall.c')
-rw-r--r-- | arch/x86_64/kernel/vsyscall.c | 45 |
1 files changed, 25 insertions, 20 deletions
diff --git a/arch/x86_64/kernel/vsyscall.c b/arch/x86_64/kernel/vsyscall.c index a98b460af6a1..a730bacecb0b 100644 --- a/arch/x86_64/kernel/vsyscall.c +++ b/arch/x86_64/kernel/vsyscall.c | |||
@@ -27,6 +27,9 @@ | |||
27 | #include <linux/jiffies.h> | 27 | #include <linux/jiffies.h> |
28 | #include <linux/sysctl.h> | 28 | #include <linux/sysctl.h> |
29 | #include <linux/getcpu.h> | 29 | #include <linux/getcpu.h> |
30 | #include <linux/cpu.h> | ||
31 | #include <linux/smp.h> | ||
32 | #include <linux/notifier.h> | ||
30 | 33 | ||
31 | #include <asm/vsyscall.h> | 34 | #include <asm/vsyscall.h> |
32 | #include <asm/pgtable.h> | 35 | #include <asm/pgtable.h> |
@@ -243,32 +246,17 @@ static ctl_table kernel_root_table2[] = { | |||
243 | 246 | ||
244 | #endif | 247 | #endif |
245 | 248 | ||
246 | static void __cpuinit write_rdtscp_cb(void *info) | 249 | /* Assume __initcall executes before all user space. Hopefully kmod |
247 | { | 250 | doesn't violate that. We'll find out if it does. */ |
248 | write_rdtscp_aux((unsigned long)info); | 251 | static void __cpuinit vsyscall_set_cpu(int cpu) |
249 | } | ||
250 | |||
251 | void __cpuinit vsyscall_set_cpu(int cpu) | ||
252 | { | 252 | { |
253 | unsigned long *d; | 253 | unsigned long *d; |
254 | unsigned long node = 0; | 254 | unsigned long node = 0; |
255 | #ifdef CONFIG_NUMA | 255 | #ifdef CONFIG_NUMA |
256 | node = cpu_to_node[cpu]; | 256 | node = cpu_to_node[cpu]; |
257 | #endif | 257 | #endif |
258 | if (cpu_has(&cpu_data[cpu], X86_FEATURE_RDTSCP)) { | 258 | if (cpu_has(&cpu_data[cpu], X86_FEATURE_RDTSCP)) |
259 | void *info = (void *)((node << 12) | cpu); | 259 | write_rdtscp_aux((node << 12) | cpu); |
260 | /* Can happen on preemptive kernel */ | ||
261 | if (get_cpu() == cpu) | ||
262 | write_rdtscp_cb(info); | ||
263 | #ifdef CONFIG_SMP | ||
264 | else { | ||
265 | /* the notifier is unfortunately not executed on the | ||
266 | target CPU */ | ||
267 | smp_call_function_single(cpu,write_rdtscp_cb,info,0,1); | ||
268 | } | ||
269 | #endif | ||
270 | put_cpu(); | ||
271 | } | ||
272 | 260 | ||
273 | /* Store cpu number in limit so that it can be loaded quickly | 261 | /* Store cpu number in limit so that it can be loaded quickly |
274 | in user space in vgetcpu. | 262 | in user space in vgetcpu. |
@@ -280,6 +268,21 @@ void __cpuinit vsyscall_set_cpu(int cpu) | |||
280 | *d |= (node >> 4) << 48; | 268 | *d |= (node >> 4) << 48; |
281 | } | 269 | } |
282 | 270 | ||
271 | static void __cpuinit cpu_vsyscall_init(void *arg) | ||
272 | { | ||
273 | /* preemption should be already off */ | ||
274 | vsyscall_set_cpu(raw_smp_processor_id()); | ||
275 | } | ||
276 | |||
277 | static int __cpuinit | ||
278 | cpu_vsyscall_notifier(struct notifier_block *n, unsigned long action, void *arg) | ||
279 | { | ||
280 | long cpu = (long)arg; | ||
281 | if (action == CPU_ONLINE) | ||
282 | smp_call_function_single(cpu, cpu_vsyscall_init, NULL, 0, 1); | ||
283 | return NOTIFY_DONE; | ||
284 | } | ||
285 | |||
283 | static void __init map_vsyscall(void) | 286 | static void __init map_vsyscall(void) |
284 | { | 287 | { |
285 | extern char __vsyscall_0; | 288 | extern char __vsyscall_0; |
@@ -299,6 +302,8 @@ static int __init vsyscall_init(void) | |||
299 | #ifdef CONFIG_SYSCTL | 302 | #ifdef CONFIG_SYSCTL |
300 | register_sysctl_table(kernel_root_table2, 0); | 303 | register_sysctl_table(kernel_root_table2, 0); |
301 | #endif | 304 | #endif |
305 | on_each_cpu(cpu_vsyscall_init, NULL, 0, 1); | ||
306 | hotcpu_notifier(cpu_vsyscall_notifier, 0); | ||
302 | return 0; | 307 | return 0; |
303 | } | 308 | } |
304 | 309 | ||