]> bbs.cooldavid.org Git - net-next-2.6.git/commitdiff
percpu: use dynamic percpu allocator as the default percpu allocator
authorTejun Heo <tj@kernel.org>
Mon, 30 Mar 2009 10:07:44 +0000 (19:07 +0900)
committerTejun Heo <tj@kernel.org>
Wed, 24 Jun 2009 06:13:35 +0000 (15:13 +0900)
This patch makes most !CONFIG_HAVE_SETUP_PER_CPU_AREA archs use
dynamic percpu allocator.  The first chunk is allocated using
embedding helper and 8k is reserved for modules.  This ensures that
the new allocator behaves almost identically to the original allocator
as long as static percpu variables are concerned, so it shouldn't
introduce much breakage.

s390 and alpha use custom SHIFT_PERCPU_PTR() to work around addressing
range limit the addressing model imposes.  Unfortunately, this breaks
if the address is specified using a variable, so for now, the two
archs aren't converted.

The following architectures are affected by this change.

* sh
* arm
* cris
* mips
* sparc(32)
* blackfin
* avr32
* parisc (broken, under investigation)
* m32r
* powerpc(32)

As this change makes the dynamic allocator the default one,
CONFIG_HAVE_DYNAMIC_PER_CPU_AREA is replaced with its invert -
CONFIG_HAVE_LEGACY_PER_CPU_AREA, which is added to yet-to-be converted
archs.  These archs implement their own setup_per_cpu_areas() and the
conversion is not trivial.

* powerpc(64)
* sparc(64)
* ia64
* alpha
* s390

Boot and batch alloc/free tests on x86_32 with debug code (x86_32
doesn't use default first chunk initialization).  Compile tested on
sparc(32), powerpc(32), arm and alpha.

Kyle McMartin reported that this change breaks parisc.  The problem is
still under investigation and he is okay with pushing this patch
forward and fixing parisc later.

[ Impact: use dynamic allocator for most archs w/o custom percpu setup ]

Signed-off-by: Tejun Heo <tj@kernel.org>
Acked-by: Rusty Russell <rusty@rustcorp.com.au>
Acked-by: David S. Miller <davem@davemloft.net>
Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Acked-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Reviewed-by: Christoph Lameter <cl@linux.com>
Cc: Paul Mundt <lethal@linux-sh.org>
Cc: Russell King <rmk@arm.linux.org.uk>
Cc: Mikael Starvik <starvik@axis.com>
Cc: Ralf Baechle <ralf@linux-mips.org>
Cc: Bryan Wu <cooloney@kernel.org>
Cc: Kyle McMartin <kyle@mcmartin.ca>
Cc: Matthew Wilcox <matthew@wil.cx>
Cc: Grant Grundler <grundler@parisc-linux.org>
Cc: Hirokazu Takata <takata@linux-m32r.org>
Cc: Richard Henderson <rth@twiddle.net>
Cc: Ivan Kokshaysky <ink@jurassic.park.msu.ru>
Cc: Heiko Carstens <heiko.carstens@de.ibm.com>
Cc: Ingo Molnar <mingo@elte.hu>
12 files changed:
arch/alpha/Kconfig
arch/ia64/Kconfig
arch/powerpc/Kconfig
arch/s390/Kconfig
arch/sparc/Kconfig
arch/x86/Kconfig
include/linux/percpu.h
init/main.c
kernel/module.c
mm/Makefile
mm/allocpercpu.c
mm/percpu.c

index 9fb8aae5c3916d4450ecc0affac8ba153f71fe29..05d86407188c0bbd331d8844c17655e46e69fa70 100644 (file)
@@ -70,6 +70,9 @@ config AUTO_IRQ_AFFINITY
        depends on SMP
        default y
 
+config HAVE_LEGACY_PER_CPU_AREA
+       def_bool y
+
 source "init/Kconfig"
 source "kernel/Kconfig.freezer"
 
index 170042b420d466829ff7baba523a7b357b43d7a5..328d2f8b8c3fafed20b504c9b3bce57ab69a519b 100644 (file)
@@ -89,6 +89,9 @@ config GENERIC_TIME_VSYSCALL
        bool
        default y
 
+config HAVE_LEGACY_PER_CPU_AREA
+       def_bool y
+
 config HAVE_SETUP_PER_CPU_AREA
        def_bool y
 
index bf6cedfa05dbfbef2073ec2b9d652dd21fac504d..a774c2acbe69993491d77eafc794889778c59943 100644 (file)
@@ -46,6 +46,9 @@ config GENERIC_HARDIRQS_NO__DO_IRQ
        bool
        default y
 
+config HAVE_LEGACY_PER_CPU_AREA
+       def_bool PPC64
+
 config HAVE_SETUP_PER_CPU_AREA
        def_bool PPC64
 
index a14dba0e4d67105c89838e8416d2dab0443640a2..f4a3cc62d28f3edb78a2576c1622793dacfbec9a 100644 (file)
@@ -75,6 +75,9 @@ config VIRT_CPU_ACCOUNTING
 config ARCH_SUPPORTS_DEBUG_PAGEALLOC
        def_bool y
 
+config HAVE_LEGACY_PER_CPU_AREA
+       def_bool y
+
 mainmenu "Linux Kernel Configuration"
 
 config S390
index 3f8b6a92eabdff56413ed4cefd54d678290a228a..7a8698b913fe7be77a3763d9dac912ba589b4af4 100644 (file)
@@ -92,6 +92,9 @@ config AUDIT_ARCH
        bool
        default y
 
+config HAVE_LEGACY_PER_CPU_AREA
+       def_bool y if SPARC64
+
 config HAVE_SETUP_PER_CPU_AREA
        def_bool y if SPARC64
 
index d1430ef6b4f9a463c7ddc3b7be49754f5fa883bd..a48a90076d83f8b8c7b5229d6ebe8c4cc321b443 100644 (file)
@@ -149,9 +149,6 @@ config ARCH_HAS_CACHE_LINE_SIZE
 config HAVE_SETUP_PER_CPU_AREA
        def_bool y
 
-config HAVE_DYNAMIC_PER_CPU_AREA
-       def_bool y
-
 config HAVE_CPUMASK_OF_CPU_MAP
        def_bool X86_64_SMP
 
index 26fd9d12f050b32a1d766071ab4e3e4fc0a1aeff..e5000343dd6199bcac26d1a4d8865ea63466cd21 100644 (file)
@@ -34,7 +34,7 @@
 
 #ifdef CONFIG_SMP
 
-#ifdef CONFIG_HAVE_DYNAMIC_PER_CPU_AREA
+#ifndef CONFIG_HAVE_LEGACY_PER_CPU_AREA
 
 /* minimum unit size, also is the maximum supported allocation size */
 #define PCPU_MIN_UNIT_SIZE             PFN_ALIGN(64 << 10)
@@ -80,7 +80,7 @@ extern ssize_t __init pcpu_embed_first_chunk(
 
 extern void *__alloc_reserved_percpu(size_t size, size_t align);
 
-#else /* CONFIG_HAVE_DYNAMIC_PER_CPU_AREA */
+#else /* CONFIG_HAVE_LEGACY_PER_CPU_AREA */
 
 struct percpu_data {
        void *ptrs[1];
@@ -99,11 +99,15 @@ struct percpu_data {
         (__typeof__(ptr))__p->ptrs[(cpu)];                             \
 })
 
-#endif /* CONFIG_HAVE_DYNAMIC_PER_CPU_AREA */
+#endif /* CONFIG_HAVE_LEGACY_PER_CPU_AREA */
 
 extern void *__alloc_percpu(size_t size, size_t align);
 extern void free_percpu(void *__pdata);
 
+#ifndef CONFIG_HAVE_SETUP_PER_CPU_AREA
+extern void __init setup_per_cpu_areas(void);
+#endif
+
 #else /* CONFIG_SMP */
 
 #define per_cpu_ptr(ptr, cpu) ({ (void)(cpu); (ptr); })
@@ -124,6 +128,8 @@ static inline void free_percpu(void *p)
        kfree(p);
 }
 
+static inline void __init setup_per_cpu_areas(void) { }
+
 #endif /* CONFIG_SMP */
 
 #define alloc_percpu(type)     (type *)__alloc_percpu(sizeof(type), \
index 09131ec090c197a33c17382544bc4ef9ac87277e..602d724afa5c985296a6bd1bf68ee9335cfeb3bf 100644 (file)
@@ -357,7 +357,6 @@ static void __init smp_init(void)
 #define smp_init()     do { } while (0)
 #endif
 
-static inline void setup_per_cpu_areas(void) { }
 static inline void setup_nr_cpu_ids(void) { }
 static inline void smp_prepare_cpus(unsigned int maxcpus) { }
 
@@ -378,29 +377,6 @@ static void __init setup_nr_cpu_ids(void)
        nr_cpu_ids = find_last_bit(cpumask_bits(cpu_possible_mask),NR_CPUS) + 1;
 }
 
-#ifndef CONFIG_HAVE_SETUP_PER_CPU_AREA
-unsigned long __per_cpu_offset[NR_CPUS] __read_mostly;
-
-EXPORT_SYMBOL(__per_cpu_offset);
-
-static void __init setup_per_cpu_areas(void)
-{
-       unsigned long size, i;
-       char *ptr;
-       unsigned long nr_possible_cpus = num_possible_cpus();
-
-       /* Copy section for each CPU (we discard the original) */
-       size = ALIGN(PERCPU_ENOUGH_ROOM, PAGE_SIZE);
-       ptr = alloc_bootmem_pages(size * nr_possible_cpus);
-
-       for_each_possible_cpu(i) {
-               __per_cpu_offset[i] = ptr - __per_cpu_start;
-               memcpy(ptr, __per_cpu_start, __per_cpu_end - __per_cpu_start);
-               ptr += size;
-       }
-}
-#endif /* CONFIG_HAVE_SETUP_PER_CPU_AREA */
-
 /* Called by boot processor to activate the rest. */
 static void __init smp_init(void)
 {
index 38928fcaff2bcb517375c3e6b19d398e4d423c05..f5934954fa99af9a886738833cc8bf386fd5e24a 100644 (file)
@@ -364,7 +364,7 @@ EXPORT_SYMBOL_GPL(find_module);
 
 #ifdef CONFIG_SMP
 
-#ifdef CONFIG_HAVE_DYNAMIC_PER_CPU_AREA
+#ifndef CONFIG_HAVE_LEGACY_PER_CPU_AREA
 
 static void *percpu_modalloc(unsigned long size, unsigned long align,
                             const char *name)
@@ -389,7 +389,7 @@ static void percpu_modfree(void *freeme)
        free_percpu(freeme);
 }
 
-#else /* ... !CONFIG_HAVE_DYNAMIC_PER_CPU_AREA */
+#else /* ... CONFIG_HAVE_LEGACY_PER_CPU_AREA */
 
 /* Number of blocks used and allocated. */
 static unsigned int pcpu_num_used, pcpu_num_allocated;
@@ -535,7 +535,7 @@ static int percpu_modinit(void)
 }
 __initcall(percpu_modinit);
 
-#endif /* CONFIG_HAVE_DYNAMIC_PER_CPU_AREA */
+#endif /* CONFIG_HAVE_LEGACY_PER_CPU_AREA */
 
 static unsigned int find_pcpusec(Elf_Ehdr *hdr,
                                 Elf_Shdr *sechdrs,
index 5e0bd64266932e54184879dff3104c372c12c152..c77c6487552f1351e4cd3881598d8f6520e69789 100644 (file)
@@ -33,7 +33,7 @@ obj-$(CONFIG_FAILSLAB) += failslab.o
 obj-$(CONFIG_MEMORY_HOTPLUG) += memory_hotplug.o
 obj-$(CONFIG_FS_XIP) += filemap_xip.o
 obj-$(CONFIG_MIGRATION) += migrate.o
-ifdef CONFIG_HAVE_DYNAMIC_PER_CPU_AREA
+ifndef CONFIG_HAVE_LEGACY_PER_CPU_AREA
 obj-$(CONFIG_SMP) += percpu.o
 else
 obj-$(CONFIG_SMP) += allocpercpu.o
index dfdee6a47359eb9f529733091b6553091a80eebc..df34ceae0c678569446930eaf5ceb982a496f8b9 100644 (file)
@@ -5,6 +5,8 @@
  */
 #include <linux/mm.h>
 #include <linux/module.h>
+#include <linux/bootmem.h>
+#include <asm/sections.h>
 
 #ifndef cache_line_size
 #define cache_line_size()      L1_CACHE_BYTES
@@ -147,3 +149,29 @@ void free_percpu(void *__pdata)
        kfree(__percpu_disguise(__pdata));
 }
 EXPORT_SYMBOL_GPL(free_percpu);
+
+/*
+ * Generic percpu area setup.
+ */
+#ifndef CONFIG_HAVE_SETUP_PER_CPU_AREA
+unsigned long __per_cpu_offset[NR_CPUS] __read_mostly;
+
+EXPORT_SYMBOL(__per_cpu_offset);
+
+void __init setup_per_cpu_areas(void)
+{
+       unsigned long size, i;
+       char *ptr;
+       unsigned long nr_possible_cpus = num_possible_cpus();
+
+       /* Copy section for each CPU (we discard the original) */
+       size = ALIGN(PERCPU_ENOUGH_ROOM, PAGE_SIZE);
+       ptr = alloc_bootmem_pages(size * nr_possible_cpus);
+
+       for_each_possible_cpu(i) {
+               __per_cpu_offset[i] = ptr - __per_cpu_start;
+               memcpy(ptr, __per_cpu_start, __per_cpu_end - __per_cpu_start);
+               ptr += size;
+       }
+}
+#endif /* CONFIG_HAVE_SETUP_PER_CPU_AREA */
index b70f2acd88535a63c0c6ffd9f41dff6e0b51da9d..b14984566f5aae5a91b83f0623ff06f7a446e253 100644 (file)
@@ -43,7 +43,7 @@
  *
  * To use this allocator, arch code should do the followings.
  *
- * - define CONFIG_HAVE_DYNAMIC_PER_CPU_AREA
+ * - drop CONFIG_HAVE_LEGACY_PER_CPU_AREA
  *
  * - define __addr_to_pcpu_ptr() and __pcpu_ptr_to_addr() to translate
  *   regular address to percpu pointer and back if they need to be
@@ -1275,3 +1275,41 @@ ssize_t __init pcpu_embed_first_chunk(size_t static_size, size_t reserved_size,
                                      reserved_size, dyn_size,
                                      pcpue_unit_size, pcpue_ptr, NULL);
 }
+
+/*
+ * Generic percpu area setup.
+ *
+ * The embedding helper is used because its behavior closely resembles
+ * the original non-dynamic generic percpu area setup.  This is
+ * important because many archs have addressing restrictions and might
+ * fail if the percpu area is located far away from the previous
+ * location.  As an added bonus, in non-NUMA cases, embedding is
+ * generally a good idea TLB-wise because percpu area can piggy back
+ * on the physical linear memory mapping which uses large page
+ * mappings on applicable archs.
+ */
+#ifndef CONFIG_HAVE_SETUP_PER_CPU_AREA
+unsigned long __per_cpu_offset[NR_CPUS] __read_mostly;
+EXPORT_SYMBOL(__per_cpu_offset);
+
+void __init setup_per_cpu_areas(void)
+{
+       size_t static_size = __per_cpu_end - __per_cpu_start;
+       ssize_t unit_size;
+       unsigned long delta;
+       unsigned int cpu;
+
+       /*
+        * Always reserve area for module percpu variables.  That's
+        * what the legacy allocator did.
+        */
+       unit_size = pcpu_embed_first_chunk(static_size, PERCPU_MODULE_RESERVE,
+                                          PERCPU_DYNAMIC_RESERVE, -1);
+       if (unit_size < 0)
+               panic("Failed to initialized percpu areas.");
+
+       delta = (unsigned long)pcpu_base_addr - (unsigned long)__per_cpu_start;
+       for_each_possible_cpu(cpu)
+               __per_cpu_offset[cpu] = delta + cpu * unit_size;
+}
+#endif /* CONFIG_HAVE_SETUP_PER_CPU_AREA */