提交 556a169d 编写于 作者: P Pekka Enberg 提交者: Linus Torvalds

slab: fix bootstrap on memoryless node

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: NMel Gorman <mel@csn.ul.ie>
Tested-by: NOlaf Hering <olaf@aepfle.de>
Reviewed-by: NChristoph Lameter <clameter@sgi.com>
Signed-off-by: NPekka Enberg <penberg@cs.helsinki.fi>
[ With additional one-liner by Olaf Hering  - Linus ]
Signed-off-by: NLinus Torvalds <torvalds@linux-foundation.org>
上级 eb36f4fc
...@@ -304,11 +304,11 @@ struct kmem_list3 { ...@@ -304,11 +304,11 @@ struct kmem_list3 {
/* /*
* Need this for bootstrapping a per node allocator. * 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]; struct kmem_list3 __initdata initkmem_list3[NUM_INIT_LISTS];
#define CACHE_CACHE 0 #define CACHE_CACHE 0
#define SIZE_AC 1 #define SIZE_AC MAX_NUMNODES
#define SIZE_L3 (1 + MAX_NUMNODES) #define SIZE_L3 (2 * MAX_NUMNODES)
static int drain_freelist(struct kmem_cache *cache, static int drain_freelist(struct kmem_cache *cache,
struct kmem_list3 *l3, int tofree); struct kmem_list3 *l3, int tofree);
...@@ -1409,6 +1409,22 @@ static void init_list(struct kmem_cache *cachep, struct kmem_list3 *list, ...@@ -1409,6 +1409,22 @@ static void init_list(struct kmem_cache *cachep, struct kmem_list3 *list,
local_irq_enable(); local_irq_enable();
} }
/*
* 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 * Initialisation. Called after the page allocator have been initialised and
* before smp_init(). * before smp_init().
...@@ -1432,6 +1448,7 @@ void __init kmem_cache_init(void) ...@@ -1432,6 +1448,7 @@ void __init kmem_cache_init(void)
if (i < MAX_NUMNODES) if (i < MAX_NUMNODES)
cache_cache.nodelists[i] = NULL; cache_cache.nodelists[i] = NULL;
} }
set_up_list3s(&cache_cache, CACHE_CACHE);
/* /*
* Fragmentation resistance on low memory - only use bigger * Fragmentation resistance on low memory - only use bigger
...@@ -1587,10 +1604,9 @@ void __init kmem_cache_init(void) ...@@ -1587,10 +1604,9 @@ void __init kmem_cache_init(void)
{ {
int nid; 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) { for_each_online_node(nid) {
init_list(&cache_cache, &initkmem_list3[CACHE_CACHE], nid);
init_list(malloc_sizes[INDEX_AC].cs_cachep, init_list(malloc_sizes[INDEX_AC].cs_cachep,
&initkmem_list3[SIZE_AC + nid], nid); &initkmem_list3[SIZE_AC + nid], nid);
...@@ -1960,22 +1976,6 @@ static void slab_destroy(struct kmem_cache *cachep, struct slab *slabp) ...@@ -1960,22 +1976,6 @@ static void slab_destroy(struct kmem_cache *cachep, struct slab *slabp)
} }
} }
/*
* 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) static void __kmem_cache_destroy(struct kmem_cache *cachep)
{ {
int i; int i;
...@@ -2099,7 +2099,7 @@ static int __init_refok setup_cpu_cache(struct kmem_cache *cachep) ...@@ -2099,7 +2099,7 @@ static int __init_refok setup_cpu_cache(struct kmem_cache *cachep)
g_cpucache_up = PARTIAL_L3; g_cpucache_up = PARTIAL_L3;
} else { } else {
int node; int node;
for_each_node_state(node, N_NORMAL_MEMORY) { for_each_online_node(node) {
cachep->nodelists[node] = cachep->nodelists[node] =
kmalloc_node(sizeof(struct kmem_list3), kmalloc_node(sizeof(struct kmem_list3),
GFP_KERNEL, node); GFP_KERNEL, node);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册