--- /dev/null
+From stable-bounces@linux.kernel.org Mon Jan 28 11:42:17 2008
+Date: Sat, 26 Jan 2008 14:15:54 +0200 (EET)
+From: Pekka J Enberg <penberg@cs.helsinki.fi>
+To: stable@kernel.org
+Message-ID: <Pine.LNX.4.64.0801261413030.19335@sbz-30.cs.Helsinki.FI>
+Cc: mel@csn.ul.ie, olaf@aepfle.de, torvalds@linux-foundation.org, clameter@sgi.com
+Subject: slab: fix bootstrap on memoryless node
+
+[ Upstream commit: 556a169dab38b5100df6f4a45b655dddd3db94c1 ]
+
+If the node we're booting on doesn't have memory, bootstrapping kmalloc()
+caches resorts to fallback_alloc() which requires ->nodelists set for all
+nodes. Fix that by calling set_up_list3s() for CACHE_CACHE in
+kmem_cache_init().
+
+As kmem_getpages() is called with GFP_THISNODE set, this used to work before
+because of breakage in 2.6.22 and before with GFP_THISNODE returning pages from
+the wrong node if a node had no memory. So it may have worked accidentally and
+in an unsafe manner because the pages would have been associated with the wrong
+node which could trigger bug ons and locking troubles.
+
+Tested-by: Mel Gorman <mel@csn.ul.ie>
+Tested-by: Olaf Hering <olaf@aepfle.de>
+Reviewed-by: Christoph Lameter <clameter@sgi.com>
+[ With additional one-liner by Olaf Hering - Linus ]
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Pekka Enberg <penberg@cs.helsinki.fi>
+Signed-off-by: Chris Wright <chrisw@sous-sol.org>
+---
+ mm/slab.c | 46 +++++++++++++++++++++++-----------------------
+ 1 file changed, 23 insertions(+), 23 deletions(-)
+
+--- linux-2.6.24.1.orig/mm/slab.c
++++ linux-2.6.24.1/mm/slab.c
+@@ -304,11 +304,11 @@ struct kmem_list3 {
+ /*
+ * Need this for bootstrapping a per node allocator.
+ */
+-#define NUM_INIT_LISTS (2 * MAX_NUMNODES + 1)
++#define NUM_INIT_LISTS (3 * MAX_NUMNODES)
+ struct kmem_list3 __initdata initkmem_list3[NUM_INIT_LISTS];
+ #define CACHE_CACHE 0
+-#define SIZE_AC 1
+-#define SIZE_L3 (1 + MAX_NUMNODES)
++#define SIZE_AC MAX_NUMNODES
++#define SIZE_L3 (2 * MAX_NUMNODES)
+
+ static int drain_freelist(struct kmem_cache *cache,
+ struct kmem_list3 *l3, int tofree);
+@@ -1410,6 +1410,22 @@ static void init_list(struct kmem_cache
+ }
+
+ /*
++ * For setting up all the kmem_list3s for cache whose buffer_size is same as
++ * size of kmem_list3.
++ */
++static void __init set_up_list3s(struct kmem_cache *cachep, int index)
++{
++ int node;
++
++ for_each_online_node(node) {
++ cachep->nodelists[node] = &initkmem_list3[index + node];
++ cachep->nodelists[node]->next_reap = jiffies +
++ REAPTIMEOUT_LIST3 +
++ ((unsigned long)cachep) % REAPTIMEOUT_LIST3;
++ }
++}
++
++/*
+ * Initialisation. Called after the page allocator have been initialised and
+ * before smp_init().
+ */
+@@ -1432,6 +1448,7 @@ void __init kmem_cache_init(void)
+ if (i < MAX_NUMNODES)
+ cache_cache.nodelists[i] = NULL;
+ }
++ set_up_list3s(&cache_cache, CACHE_CACHE);
+
+ /*
+ * Fragmentation resistance on low memory - only use bigger
+@@ -1587,10 +1604,9 @@ void __init kmem_cache_init(void)
+ {
+ int nid;
+
+- /* Replace the static kmem_list3 structures for the boot cpu */
+- init_list(&cache_cache, &initkmem_list3[CACHE_CACHE], node);
+-
+ for_each_online_node(nid) {
++ init_list(&cache_cache, &initkmem_list3[CACHE_CACHE], nid);
++
+ init_list(malloc_sizes[INDEX_AC].cs_cachep,
+ &initkmem_list3[SIZE_AC + nid], nid);
+
+@@ -1960,22 +1976,6 @@ static void slab_destroy(struct kmem_cac
+ }
+ }
+
+-/*
+- * For setting up all the kmem_list3s for cache whose buffer_size is same as
+- * size of kmem_list3.
+- */
+-static void __init set_up_list3s(struct kmem_cache *cachep, int index)
+-{
+- int node;
+-
+- for_each_online_node(node) {
+- cachep->nodelists[node] = &initkmem_list3[index + node];
+- cachep->nodelists[node]->next_reap = jiffies +
+- REAPTIMEOUT_LIST3 +
+- ((unsigned long)cachep) % REAPTIMEOUT_LIST3;
+- }
+-}
+-
+ static void __kmem_cache_destroy(struct kmem_cache *cachep)
+ {
+ int i;
+@@ -2099,7 +2099,7 @@ static int __init_refok setup_cpu_cache(
+ g_cpucache_up = PARTIAL_L3;
+ } else {
+ int node;
+- for_each_node_state(node, N_NORMAL_MEMORY) {
++ for_each_online_node(node) {
+ cachep->nodelists[node] =
+ kmalloc_node(sizeof(struct kmem_list3),
+ GFP_KERNEL, node);