slab: Simplify bootstrap
authorChristoph Lameter <cl@linux.com>
Wed, 28 Nov 2012 16:23:01 +0000 (16:23 +0000)
committerPekka Enberg <penberg@kernel.org>
Tue, 11 Dec 2012 10:14:27 +0000 (12:14 +0200)
The nodelists field in kmem_cache is pointing to the first unused
object in the array field when bootstrap is complete.

A problem with the current approach is that the statically sized
kmem_cache structure use on boot can only contain NR_CPUS entries.
If the number of nodes plus the number of cpus is greater then we
would overwrite memory following the kmem_cache_boot definition.

Increase the size of the array field to ensure that also the node
pointers fit into the array field.

Once we do that we no longer need the kmem_cache_nodelists
array and we can then also use that structure elsewhere.

Acked-by: Glauber Costa <glommer@parallels.com>
Signed-off-by: Christoph Lameter <cl@linux.com>
Signed-off-by: Pekka Enberg <penberg@kernel.org>
include/linux/slab_def.h
mm/slab.c

index cc290f0bdb346efe82dbe0e87985e6d015ad58e1..45c0356fdc8c086f8b392b5ff6c8813a01679a32 100644 (file)
@@ -89,9 +89,13 @@ struct kmem_cache {
         * (see kmem_cache_init())
         * We still use [NR_CPUS] and not [1] or [0] because cache_cache
         * is statically defined, so we reserve the max number of cpus.
+        *
+        * We also need to guarantee that the list is able to accomodate a
+        * pointer for each node since "nodelists" uses the remainder of
+        * available pointers.
         */
        struct kmem_list3 **nodelists;
-       struct array_cache *array[NR_CPUS];
+       struct array_cache *array[NR_CPUS + MAX_NUMNODES];
        /*
         * Do not add fields after array[]
         */
index e26bff5ed1a63945786af477d59bd26991b0bea7..c7ea5234c4e904c7384bf2bade161866f7f32699 100644 (file)
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -553,9 +553,7 @@ static struct arraycache_init initarray_generic =
     { {0, BOOT_CPUCACHE_ENTRIES, 1, 0} };
 
 /* internal cache of cache description objs */
-static struct kmem_list3 *kmem_cache_nodelists[MAX_NUMNODES];
 static struct kmem_cache kmem_cache_boot = {
-       .nodelists = kmem_cache_nodelists,
        .batchcount = 1,
        .limit = BOOT_CPUCACHE_ENTRIES,
        .shared = 1,
@@ -1559,6 +1557,15 @@ static void __init set_up_list3s(struct kmem_cache *cachep, int index)
        }
 }
 
+/*
+ * The memory after the last cpu cache pointer is used for the
+ * the nodelists pointer.
+ */
+static void setup_nodelists_pointer(struct kmem_cache *cachep)
+{
+       cachep->nodelists = (struct kmem_list3 **)&cachep->array[nr_cpu_ids];
+}
+
 /*
  * Initialisation.  Called after the page allocator have been initialised and
  * before smp_init().
@@ -1573,15 +1580,14 @@ void __init kmem_cache_init(void)
        int node;
 
        kmem_cache = &kmem_cache_boot;
+       setup_nodelists_pointer(kmem_cache);
 
        if (num_possible_nodes() == 1)
                use_alien_caches = 0;
 
-       for (i = 0; i < NUM_INIT_LISTS; i++) {
+       for (i = 0; i < NUM_INIT_LISTS; i++)
                kmem_list3_init(&initkmem_list3[i]);
-               if (i < MAX_NUMNODES)
-                       kmem_cache->nodelists[i] = NULL;
-       }
+
        set_up_list3s(kmem_cache, CACHE_CACHE);
 
        /*
@@ -1619,7 +1625,6 @@ void __init kmem_cache_init(void)
        list_add(&kmem_cache->list, &slab_caches);
        kmem_cache->colour_off = cache_line_size();
        kmem_cache->array[smp_processor_id()] = &initarray_cache.cache;
-       kmem_cache->nodelists[node] = &initkmem_list3[CACHE_CACHE + node];
 
        /*
         * struct kmem_cache size depends on nr_node_ids & nr_cpu_ids
@@ -2422,7 +2427,7 @@ __kmem_cache_create (struct kmem_cache *cachep, unsigned long flags)
        else
                gfp = GFP_NOWAIT;
 
-       cachep->nodelists = (struct kmem_list3 **)&cachep->array[nr_cpu_ids];
+       setup_nodelists_pointer(cachep);
 #if DEBUG
 
        /*