aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/module.h11
-rw-r--r--include/linux/percpu.h7
-rw-r--r--kernel/lockdep.c21
-rw-r--r--kernel/module.c104
-rw-r--r--mm/percpu.c26
-rw-r--r--mm/rmap.c1
6 files changed, 122 insertions, 48 deletions
diff --git a/include/linux/module.h b/include/linux/module.h
index 5e869ffd34aa..8bd399a00343 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -330,8 +330,11 @@ struct module
330 struct module_notes_attrs *notes_attrs; 330 struct module_notes_attrs *notes_attrs;
331#endif 331#endif
332 332
333#ifdef CONFIG_SMP
333 /* Per-cpu data. */ 334 /* Per-cpu data. */
334 void *percpu; 335 void __percpu *percpu;
336 unsigned int percpu_size;
337#endif
335 338
336 /* The command line arguments (may be mangled). People like 339 /* The command line arguments (may be mangled). People like
337 keeping pointers to this stuff */ 340 keeping pointers to this stuff */
@@ -392,6 +395,7 @@ static inline int module_is_live(struct module *mod)
392struct module *__module_text_address(unsigned long addr); 395struct module *__module_text_address(unsigned long addr);
393struct module *__module_address(unsigned long addr); 396struct module *__module_address(unsigned long addr);
394bool is_module_address(unsigned long addr); 397bool is_module_address(unsigned long addr);
398bool is_module_percpu_address(unsigned long addr);
395bool is_module_text_address(unsigned long addr); 399bool is_module_text_address(unsigned long addr);
396 400
397static inline int within_module_core(unsigned long addr, struct module *mod) 401static inline int within_module_core(unsigned long addr, struct module *mod)
@@ -563,6 +567,11 @@ static inline bool is_module_address(unsigned long addr)
563 return false; 567 return false;
564} 568}
565 569
570static inline bool is_module_percpu_address(unsigned long addr)
571{
572 return false;
573}
574
566static inline bool is_module_text_address(unsigned long addr) 575static inline bool is_module_text_address(unsigned long addr)
567{ 576{
568 return false; 577 return false;
diff --git a/include/linux/percpu.h b/include/linux/percpu.h
index c7845130bfdf..d3a38d687104 100644
--- a/include/linux/percpu.h
+++ b/include/linux/percpu.h
@@ -135,6 +135,7 @@ extern int __init pcpu_page_first_chunk(size_t reserved_size,
135#define per_cpu_ptr(ptr, cpu) SHIFT_PERCPU_PTR((ptr), per_cpu_offset((cpu))) 135#define per_cpu_ptr(ptr, cpu) SHIFT_PERCPU_PTR((ptr), per_cpu_offset((cpu)))
136 136
137extern void __percpu *__alloc_reserved_percpu(size_t size, size_t align); 137extern void __percpu *__alloc_reserved_percpu(size_t size, size_t align);
138extern bool is_kernel_percpu_address(unsigned long addr);
138 139
139#ifndef CONFIG_HAVE_SETUP_PER_CPU_AREA 140#ifndef CONFIG_HAVE_SETUP_PER_CPU_AREA
140extern void __init setup_per_cpu_areas(void); 141extern void __init setup_per_cpu_areas(void);
@@ -144,6 +145,12 @@ extern void __init setup_per_cpu_areas(void);
144 145
145#define per_cpu_ptr(ptr, cpu) ({ (void)(cpu); (ptr); }) 146#define per_cpu_ptr(ptr, cpu) ({ (void)(cpu); (ptr); })
146 147
148/* can't distinguish from other static vars, always false */
149static inline bool is_kernel_percpu_address(unsigned long addr)
150{
151 return false;
152}
153
147static inline void __init setup_per_cpu_areas(void) { } 154static inline void __init setup_per_cpu_areas(void) { }
148 155
149static inline void *pcpu_lpage_remapped(void *kaddr) 156static inline void *pcpu_lpage_remapped(void *kaddr)
diff --git a/kernel/lockdep.c b/kernel/lockdep.c
index 367f72452ff4..2594e1ce41cb 100644
--- a/kernel/lockdep.c
+++ b/kernel/lockdep.c
@@ -583,9 +583,6 @@ static int static_obj(void *obj)
583 unsigned long start = (unsigned long) &_stext, 583 unsigned long start = (unsigned long) &_stext,
584 end = (unsigned long) &_end, 584 end = (unsigned long) &_end,
585 addr = (unsigned long) obj; 585 addr = (unsigned long) obj;
586#ifdef CONFIG_SMP
587 int i;
588#endif
589 586
590 /* 587 /*
591 * static variable? 588 * static variable?
@@ -596,24 +593,16 @@ static int static_obj(void *obj)
596 if (arch_is_kernel_data(addr)) 593 if (arch_is_kernel_data(addr))
597 return 1; 594 return 1;
598 595
599#ifdef CONFIG_SMP
600 /* 596 /*
601 * percpu var? 597 * in-kernel percpu var?
602 */ 598 */
603 for_each_possible_cpu(i) { 599 if (is_kernel_percpu_address(addr))
604 start = (unsigned long) &__per_cpu_start + per_cpu_offset(i); 600 return 1;
605 end = (unsigned long) &__per_cpu_start + PERCPU_ENOUGH_ROOM
606 + per_cpu_offset(i);
607
608 if ((addr >= start) && (addr < end))
609 return 1;
610 }
611#endif
612 601
613 /* 602 /*
614 * module var? 603 * module static or percpu var?
615 */ 604 */
616 return is_module_address(addr); 605 return is_module_address(addr) || is_module_percpu_address(addr);
617} 606}
618 607
619/* 608/*
diff --git a/kernel/module.c b/kernel/module.c
index c968d3606dca..9f8d23d8b3a8 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -370,27 +370,33 @@ EXPORT_SYMBOL_GPL(find_module);
370 370
371#ifdef CONFIG_SMP 371#ifdef CONFIG_SMP
372 372
373static void *percpu_modalloc(unsigned long size, unsigned long align, 373static inline void __percpu *mod_percpu(struct module *mod)
374 const char *name)
375{ 374{
376 void *ptr; 375 return mod->percpu;
376}
377 377
378static int percpu_modalloc(struct module *mod,
379 unsigned long size, unsigned long align)
380{
378 if (align > PAGE_SIZE) { 381 if (align > PAGE_SIZE) {
379 printk(KERN_WARNING "%s: per-cpu alignment %li > %li\n", 382 printk(KERN_WARNING "%s: per-cpu alignment %li > %li\n",
380 name, align, PAGE_SIZE); 383 mod->name, align, PAGE_SIZE);
381 align = PAGE_SIZE; 384 align = PAGE_SIZE;
382 } 385 }
383 386
384 ptr = __alloc_reserved_percpu(size, align); 387 mod->percpu = __alloc_reserved_percpu(size, align);
385 if (!ptr) 388 if (!mod->percpu) {
386 printk(KERN_WARNING 389 printk(KERN_WARNING
387 "Could not allocate %lu bytes percpu data\n", size); 390 "Could not allocate %lu bytes percpu data\n", size);
388 return ptr; 391 return -ENOMEM;
392 }
393 mod->percpu_size = size;
394 return 0;
389} 395}
390 396
391static void percpu_modfree(void *freeme) 397static void percpu_modfree(struct module *mod)
392{ 398{
393 free_percpu(freeme); 399 free_percpu(mod->percpu);
394} 400}
395 401
396static unsigned int find_pcpusec(Elf_Ehdr *hdr, 402static unsigned int find_pcpusec(Elf_Ehdr *hdr,
@@ -400,24 +406,62 @@ static unsigned int find_pcpusec(Elf_Ehdr *hdr,
400 return find_sec(hdr, sechdrs, secstrings, ".data.percpu"); 406 return find_sec(hdr, sechdrs, secstrings, ".data.percpu");
401} 407}
402 408
403static void percpu_modcopy(void *pcpudest, const void *from, unsigned long size) 409static void percpu_modcopy(struct module *mod,
410 const void *from, unsigned long size)
404{ 411{
405 int cpu; 412 int cpu;
406 413
407 for_each_possible_cpu(cpu) 414 for_each_possible_cpu(cpu)
408 memcpy(pcpudest + per_cpu_offset(cpu), from, size); 415 memcpy(per_cpu_ptr(mod->percpu, cpu), from, size);
416}
417
418/**
419 * is_module_percpu_address - test whether address is from module static percpu
420 * @addr: address to test
421 *
422 * Test whether @addr belongs to module static percpu area.
423 *
424 * RETURNS:
425 * %true if @addr is from module static percpu area
426 */
427bool is_module_percpu_address(unsigned long addr)
428{
429 struct module *mod;
430 unsigned int cpu;
431
432 preempt_disable();
433
434 list_for_each_entry_rcu(mod, &modules, list) {
435 if (!mod->percpu_size)
436 continue;
437 for_each_possible_cpu(cpu) {
438 void *start = per_cpu_ptr(mod->percpu, cpu);
439
440 if ((void *)addr >= start &&
441 (void *)addr < start + mod->percpu_size) {
442 preempt_enable();
443 return true;
444 }
445 }
446 }
447
448 preempt_enable();
449 return false;
409} 450}
410 451
411#else /* ... !CONFIG_SMP */ 452#else /* ... !CONFIG_SMP */
412 453
413static inline void *percpu_modalloc(unsigned long size, unsigned long align, 454static inline void __percpu *mod_percpu(struct module *mod)
414 const char *name)
415{ 455{
416 return NULL; 456 return NULL;
417} 457}
418static inline void percpu_modfree(void *pcpuptr) 458static inline int percpu_modalloc(struct module *mod,
459 unsigned long size, unsigned long align)
460{
461 return -ENOMEM;
462}
463static inline void percpu_modfree(struct module *mod)
419{ 464{
420 BUG();
421} 465}
422static inline unsigned int find_pcpusec(Elf_Ehdr *hdr, 466static inline unsigned int find_pcpusec(Elf_Ehdr *hdr,
423 Elf_Shdr *sechdrs, 467 Elf_Shdr *sechdrs,
@@ -425,12 +469,16 @@ static inline unsigned int find_pcpusec(Elf_Ehdr *hdr,
425{ 469{
426 return 0; 470 return 0;
427} 471}
428static inline void percpu_modcopy(void *pcpudst, const void *src, 472static inline void percpu_modcopy(struct module *mod,
429 unsigned long size) 473 const void *from, unsigned long size)
430{ 474{
431 /* pcpusec should be 0, and size of that section should be 0. */ 475 /* pcpusec should be 0, and size of that section should be 0. */
432 BUG_ON(size != 0); 476 BUG_ON(size != 0);
433} 477}
478bool is_module_percpu_address(unsigned long addr)
479{
480 return false;
481}
434 482
435#endif /* CONFIG_SMP */ 483#endif /* CONFIG_SMP */
436 484
@@ -1400,8 +1448,7 @@ static void free_module(struct module *mod)
1400 /* This may be NULL, but that's OK */ 1448 /* This may be NULL, but that's OK */
1401 module_free(mod, mod->module_init); 1449 module_free(mod, mod->module_init);
1402 kfree(mod->args); 1450 kfree(mod->args);
1403 if (mod->percpu) 1451 percpu_modfree(mod);
1404 percpu_modfree(mod->percpu);
1405#if defined(CONFIG_MODULE_UNLOAD) 1452#if defined(CONFIG_MODULE_UNLOAD)
1406 if (mod->refptr) 1453 if (mod->refptr)
1407 free_percpu(mod->refptr); 1454 free_percpu(mod->refptr);
@@ -1520,7 +1567,7 @@ static int simplify_symbols(Elf_Shdr *sechdrs,
1520 default: 1567 default:
1521 /* Divert to percpu allocation if a percpu var. */ 1568 /* Divert to percpu allocation if a percpu var. */
1522 if (sym[i].st_shndx == pcpuindex) 1569 if (sym[i].st_shndx == pcpuindex)
1523 secbase = (unsigned long)mod->percpu; 1570 secbase = (unsigned long)mod_percpu(mod);
1524 else 1571 else
1525 secbase = sechdrs[sym[i].st_shndx].sh_addr; 1572 secbase = sechdrs[sym[i].st_shndx].sh_addr;
1526 sym[i].st_value += secbase; 1573 sym[i].st_value += secbase;
@@ -1954,7 +2001,7 @@ static noinline struct module *load_module(void __user *umod,
1954 unsigned int modindex, versindex, infoindex, pcpuindex; 2001 unsigned int modindex, versindex, infoindex, pcpuindex;
1955 struct module *mod; 2002 struct module *mod;
1956 long err = 0; 2003 long err = 0;
1957 void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */ 2004 void *ptr = NULL; /* Stops spurious gcc warning */
1958 unsigned long symoffs, stroffs, *strmap; 2005 unsigned long symoffs, stroffs, *strmap;
1959 2006
1960 mm_segment_t old_fs; 2007 mm_segment_t old_fs;
@@ -2094,15 +2141,11 @@ static noinline struct module *load_module(void __user *umod,
2094 2141
2095 if (pcpuindex) { 2142 if (pcpuindex) {
2096 /* We have a special allocation for this section. */ 2143 /* We have a special allocation for this section. */
2097 percpu = percpu_modalloc(sechdrs[pcpuindex].sh_size, 2144 err = percpu_modalloc(mod, sechdrs[pcpuindex].sh_size,
2098 sechdrs[pcpuindex].sh_addralign, 2145 sechdrs[pcpuindex].sh_addralign);
2099 mod->name); 2146 if (err)
2100 if (!percpu) {
2101 err = -ENOMEM;
2102 goto free_mod; 2147 goto free_mod;
2103 }
2104 sechdrs[pcpuindex].sh_flags &= ~(unsigned long)SHF_ALLOC; 2148 sechdrs[pcpuindex].sh_flags &= ~(unsigned long)SHF_ALLOC;
2105 mod->percpu = percpu;
2106 } 2149 }
2107 2150
2108 /* Determine total sizes, and put offsets in sh_entsize. For now 2151 /* Determine total sizes, and put offsets in sh_entsize. For now
@@ -2317,7 +2360,7 @@ static noinline struct module *load_module(void __user *umod,
2317 sort_extable(mod->extable, mod->extable + mod->num_exentries); 2360 sort_extable(mod->extable, mod->extable + mod->num_exentries);
2318 2361
2319 /* Finally, copy percpu area over. */ 2362 /* Finally, copy percpu area over. */
2320 percpu_modcopy(mod->percpu, (void *)sechdrs[pcpuindex].sh_addr, 2363 percpu_modcopy(mod, (void *)sechdrs[pcpuindex].sh_addr,
2321 sechdrs[pcpuindex].sh_size); 2364 sechdrs[pcpuindex].sh_size);
2322 2365
2323 add_kallsyms(mod, sechdrs, hdr->e_shnum, symindex, strindex, 2366 add_kallsyms(mod, sechdrs, hdr->e_shnum, symindex, strindex,
@@ -2409,8 +2452,7 @@ static noinline struct module *load_module(void __user *umod,
2409 module_free(mod, mod->module_core); 2452 module_free(mod, mod->module_core);
2410 /* mod will be freed with core. Don't access it beyond this line! */ 2453 /* mod will be freed with core. Don't access it beyond this line! */
2411 free_percpu: 2454 free_percpu:
2412 if (percpu) 2455 percpu_modfree(mod);
2413 percpu_modfree(percpu);
2414 free_mod: 2456 free_mod:
2415 kfree(args); 2457 kfree(args);
2416 kfree(strmap); 2458 kfree(strmap);
diff --git a/mm/percpu.c b/mm/percpu.c
index 768419d44ad7..6e09741ddc62 100644
--- a/mm/percpu.c
+++ b/mm/percpu.c
@@ -1304,6 +1304,32 @@ void free_percpu(void __percpu *ptr)
1304EXPORT_SYMBOL_GPL(free_percpu); 1304EXPORT_SYMBOL_GPL(free_percpu);
1305 1305
1306/** 1306/**
1307 * is_kernel_percpu_address - test whether address is from static percpu area
1308 * @addr: address to test
1309 *
1310 * Test whether @addr belongs to in-kernel static percpu area. Module
1311 * static percpu areas are not considered. For those, use
1312 * is_module_percpu_address().
1313 *
1314 * RETURNS:
1315 * %true if @addr is from in-kernel static percpu area, %false otherwise.
1316 */
1317bool is_kernel_percpu_address(unsigned long addr)
1318{
1319 const size_t static_size = __per_cpu_end - __per_cpu_start;
1320 void __percpu *base = __addr_to_pcpu_ptr(pcpu_base_addr);
1321 unsigned int cpu;
1322
1323 for_each_possible_cpu(cpu) {
1324 void *start = per_cpu_ptr(base, cpu);
1325
1326 if ((void *)addr >= start && (void *)addr < start + static_size)
1327 return true;
1328 }
1329 return false;
1330}
1331
1332/**
1307 * per_cpu_ptr_to_phys - convert translated percpu address to physical address 1333 * per_cpu_ptr_to_phys - convert translated percpu address to physical address
1308 * @addr: the address to be converted to physical address 1334 * @addr: the address to be converted to physical address
1309 * 1335 *
diff --git a/mm/rmap.c b/mm/rmap.c
index fcd593c9c997..eaa7a09eb72e 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -232,6 +232,7 @@ int anon_vma_fork(struct vm_area_struct *vma, struct vm_area_struct *pvma)
232 out_error_free_anon_vma: 232 out_error_free_anon_vma:
233 anon_vma_free(anon_vma); 233 anon_vma_free(anon_vma);
234 out_error: 234 out_error:
235 unlink_anon_vmas(vma);
235 return -ENOMEM; 236 return -ENOMEM;
236} 237}
237 238