Index: linux-2.6.21-rc5-mm3/include/linux/mmzone.h =================================================================== --- linux-2.6.21-rc5-mm3.orig/include/linux/mmzone.h 2007-03-30 21:50:18.000000000 -0700 +++ linux-2.6.21-rc5-mm3/include/linux/mmzone.h 2007-03-30 22:34:17.000000000 -0700 @@ -45,6 +45,15 @@ for (order = 0; order < MAX_ORDER; order++) \ for (type = 0; type < MIGRATE_TYPES; type++) +#define MAX_SLAB_CACHES 256 + +struct kmem_cache_node { + spinlock_t list_lock; /* Protect partial list and nr_partial */ + unsigned long nr_partial; + atomic_long_t nr_slabs; + struct list_head partial; +}; + struct free_area { struct list_head free_list[MIGRATE_TYPES]; unsigned long nr_free; @@ -481,6 +490,9 @@ typedef struct pglist_data { wait_queue_head_t kswapd_wait; struct task_struct *kswapd; int kswapd_max_order; +#ifdef CONFIG_SLUB + struct kmem_cache_node slabs[MAX_SLAB_CACHES]; +#endif } pg_data_t; #define node_present_pages(nid) (NODE_DATA(nid)->node_present_pages) Index: linux-2.6.21-rc5-mm3/include/linux/slub_def.h =================================================================== --- linux-2.6.21-rc5-mm3.orig/include/linux/slub_def.h 2007-03-30 22:31:02.000000000 -0700 +++ linux-2.6.21-rc5-mm3/include/linux/slub_def.h 2007-03-30 22:35:31.000000000 -0700 @@ -11,13 +11,6 @@ #include #include -struct kmem_cache_node { - spinlock_t list_lock; /* Protect partial list and nr_partial */ - unsigned long nr_partial; - atomic_long_t nr_slabs; - struct list_head partial; -}; - /* * Slab cache management. */ @@ -31,12 +24,6 @@ struct kmem_cache { int defrag_ratio; unsigned int order; - /* - * Avoid an extra cache line for UP, SMP and for the node local to - * struct kmem_cache. - */ - struct kmem_cache_node local_node; - /* Allocation and freeing of slabs */ int objects; /* Number of objects in slab */ int refcount; /* Refcount for slab cache destroy */ @@ -52,10 +39,6 @@ struct kmem_cache { struct delayed_work flush; struct mutex flushing; #endif -#ifdef CONFIG_NUMA - struct kmem_cache_node *node[MAX_NUMNODES]; -#endif - struct page *cpu_slab[NR_CPUS]; }; /* @@ -150,7 +133,7 @@ static inline struct kmem_cache *kmalloc extern void __kmalloc_size_too_large(void); __kmalloc_size_too_large(); } - return &kmalloc_caches[index]; + return slub_caches + index; } #ifdef CONFIG_ZONE_DMA Index: linux-2.6.21-rc5-mm3/mm/slub.c =================================================================== --- linux-2.6.21-rc5-mm3.orig/mm/slub.c 2007-03-30 22:31:12.000000000 -0700 +++ linux-2.6.21-rc5-mm3/mm/slub.c 2007-03-30 22:34:17.000000000 -0700 @@ -104,8 +104,6 @@ /* Internal SLUB flags */ #define __OBJECT_POISON 0x80000000 /* Poison object */ -static int kmem_size = sizeof(struct kmem_cache); - #ifdef CONFIG_SMP static struct notifier_block slab_notifier; #endif @@ -123,7 +121,8 @@ int slab_is_available(void) { /* A list of all slab caches on the system */ static DECLARE_RWSEM(slub_lock); -LIST_HEAD(slab_caches); + +static DEFINE_PER_CPU(struct page *, cpu_slab)[MAX_SLAB_CACHES]; #ifdef CONFIG_SYSFS static int sysfs_slab_add(struct kmem_cache *); @@ -141,13 +140,14 @@ static void setup_slab_die(void) {}; * Core slab cache functions *******************************************************************/ -struct kmem_cache_node *get_node(struct kmem_cache *s, int node) +static inline struct page **get_cpu_slab(struct kmem_cache *s) { -#ifdef CONFIG_NUMA - return s->node[node]; -#else - return &s->local_node; -#endif + return &__get_cpu_var(cpu_slab)[s - slub_caches]; +} + +static inline struct kmem_cache_node *get_node(struct kmem_cache *s, int node) +{ + return &NODE_DATA(node)->slabs[s - slub_caches]; } /* @@ -1045,13 +1045,13 @@ static void flush_cpu_slab(void *d) static void check_flush_cpu_slab(void *private) { struct kmem_cache *s = private; - int cpu = smp_processor_id(); - struct page *page = s->cpu_slab[cpu]; + struct page **ppage = get_cpu_slab(s); + struct page *page = *ppage; if (page) { if (!TestClearPageReferenced(page)) return; - flush_slab(s, page, cpu); + flush_slab(s, page, ppage); } atomic_dec(&s->cpu_slabs); } @@ -1111,13 +1111,13 @@ static __always_inline void *slab_alloc( gfp_t gfpflags, int node) { struct page *page; + struct page **ppage; void **object; unsigned long flags; - int cpu; local_irq_save(flags); - cpu = smp_processor_id(); - page = s->cpu_slab[cpu]; + ppage = get_cpu_slab(s); + page = *ppage; if (!page) goto new_slab; @@ -1140,7 +1140,7 @@ have_object: return object; another_slab: - deactivate_slab(s, page, cpu); + deactivate_slab(s, page, ppage); new_slab: page = get_partial(s, gfpflags, node); @@ -1528,7 +1528,7 @@ static int kmem_cache_open(struct kmem_c void (*ctor)(void *, struct kmem_cache *, unsigned long), void (*dtor)(void *, struct kmem_cache *, unsigned long)) { - memset(s, 0, kmem_size); + memset(s, 0, sizeof(struct kmem_cache)); s->name = name; s->ctor = ctor; s->dtor = dtor; @@ -1661,7 +1661,6 @@ static int kmem_cache_close(struct kmem_ if (atomic_long_read(&n->nr_slabs)) return 1; } - free_kmem_cache_nodes(s); return 0; } EXPORT_SYMBOL(kmem_cache_close); @@ -1783,7 +1782,6 @@ static struct kmem_cache *create_kmalloc flags, NULL, NULL)) goto panic; - list_add(&s->list, &slab_caches); up_write(&slub_lock); if (sysfs_slab_add(s)) goto panic; @@ -1856,6 +1854,7 @@ void *__kmalloc_node(size_t size, gfp_t if (s) return kmem_cache_alloc_node(s, flags, node); + return NULL; } EXPORT_SYMBOL(__kmalloc_node); @@ -2023,7 +2022,7 @@ static struct kmem_cache *find_mergeable void (*ctor)(void *, struct kmem_cache *, unsigned long), void (*dtor)(void *, struct kmem_cache *, unsigned long)) { - struct list_head *h; + struct kmem_cache *s; if (slub_nomerge || (flags & SLUB_NEVER_MERGE)) return NULL; @@ -2035,9 +2034,9 @@ static struct kmem_cache *find_mergeable align = calculate_alignment(flags, align); size = ALIGN(size, align); - list_for_each(h, &slab_caches) { - struct kmem_cache *s = - container_of(h, struct kmem_cache, list); + for(s = slub_caches; s < slub_caches + MAX_SLAB_CACHES; s++) { + if (!s->refcount) + continue; if (size > s->size) continue; @@ -2066,6 +2065,18 @@ static struct kmem_cache *find_mergeable return NULL; } +int reserved_slab(struct kmem_cache *s) +{ +#ifdef CONFIG_ZONE_DMA + if (s > slub_caches + 2 * KMALLOC_SHIFT_HIGH) + return 0; + if (s < slub_caches + KMALLOC_SHIFT_HIGH) + return 0; + return 1; +#else + return 0; +#endif +} struct kmem_cache *kmem_cache_create(const char *name, size_t size, size_t align, unsigned long flags, void (*ctor)(void *, struct kmem_cache *, unsigned long), @@ -2086,16 +2097,17 @@ struct kmem_cache *kmem_cache_create(con if (sysfs_slab_alias(s, name)) goto err; } else { - s = kmalloc(kmem_size, GFP_KERNEL); - if (s && kmem_cache_open(s, GFP_KERNEL, name, + for(s = slub_caches; s < slub_caches + MAX_SLAB_CACHES; s++) + if (!s->refcount && !reserved_slab(s)) + break; + BUG_ON(s >= slub_caches + MAX_SLAB_CACHES); + if (kmem_cache_open(s, GFP_KERNEL, name, size, align, flags, ctor, dtor)) { if (sysfs_slab_add(s)) { kfree(s); goto err; } - list_add(&s->list, &slab_caches); - } else - kfree(s); + } } up_write(&slub_lock); return s; @@ -2122,17 +2134,15 @@ void *kmem_cache_zalloc(struct kmem_cach EXPORT_SYMBOL(kmem_cache_zalloc); #ifdef CONFIG_SMP -static void for_all_slabs(void (*func)(struct kmem_cache *, int), int cpu) +static void for_all_slabs(void (*func)(struct kmem_cache *, struct page **), + struct page **ppage) { - struct list_head *h; + struct kmem_cache *s; down_read(&slub_lock); - list_for_each(h, &slab_caches) { - struct kmem_cache *s = - container_of(h, struct kmem_cache, list); - - func(s, cpu); - } + for (s = slub_caches; s + MAX_SLAB_CACHES; s++) + if (s->refcount) + func(s, ppage + (s - slub_caches)); up_read(&slub_lock); } @@ -2148,7 +2158,7 @@ static int __cpuinit slab_cpuup_callback switch (action) { case CPU_UP_CANCELED: case CPU_DEAD: - for_all_slabs(__flush_cpu_slab, cpu); + for_all_slabs(__flush_cpu_slab, per_cpu(cpu_slab, cpu)); break; default: break; @@ -2359,7 +2369,7 @@ static unsigned long slab_objects(struct if (flags & SO_CPU) for_each_possible_cpu(cpu) { - struct page *page = s->cpu_slab[cpu]; + struct page *page = per_cpu(cpu_slab, cpu)[s - slub_caches]; if (page) { int x = 0; @@ -2391,7 +2401,7 @@ static int any_slab_objects(struct kmem_ int cpu; for_each_possible_cpu(cpu) - if (s->cpu_slab[cpu]) + if (per_cpu(cpu_slab, cpu)[s - slub_caches]) return 1; for_each_node(node) { @@ -2466,8 +2476,11 @@ static int slab_die_call(struct notifier { struct kmem_cache *s; - list_for_each_entry(s, &slab_caches, list) + for(s = slub_caches; s < slub_caches + MAX_SLAB_CACHES; s++) { + if (!s->refcount) + continue; validate_slab_cache(s); + } return NOTIFY_OK; } @@ -2863,7 +2876,7 @@ int sysfs_slab_alias(struct kmem_cache * int __init slab_sysfs_init(void) { int err; - struct list_head *h; + struct kmem_cache *s; err = subsystem_register(&slab_subsys); if (err) { @@ -2873,9 +2886,9 @@ int __init slab_sysfs_init(void) slab_state = SYSFS; - list_for_each(h, &slab_caches) { - struct kmem_cache *s = - container_of(h, struct kmem_cache, list); + for(s = slub_caches; s < slub_caches + MAX_SLAB_CACHES; s++) { + if (!s->refcount) + continue; err = sysfs_slab_add(s); BUG_ON(err);