Index: linux-2.6.19-mm1/mm/slub.c =================================================================== --- linux-2.6.19-mm1.orig/mm/slub.c 2006-12-13 16:29:44.000000000 -0800 +++ linux-2.6.19-mm1/mm/slub.c 2006-12-13 17:44:26.000000000 -0800 @@ -185,8 +185,8 @@ */ static __always_inline void slab_lock(struct page *page) { -// bit_spin_lock(PG_locked, &page->flags); - BUG_ON(!bit_spin_trylock(PG_locked, &page->flags)); + bit_spin_lock(PG_locked, &page->flags); +// BUG_ON(!bit_spin_trylock(PG_locked, &page->flags)); } static __always_inline void slab_unlock(struct page *page) @@ -230,44 +230,26 @@ return 0; } -/* - * Get a partial page, lock it and return it. - */ -#ifdef CONFIG_NUMA -static struct page *get_partial(struct kmem_cache *s, gfp_t flags, int node) +struct page *numa_partial(struct kmem_cache *s, gfp_t flags, int node) { - struct page *page; +#ifdef CONFIG_NUMA int searchnode = (node == -1) ? numa_node_id() : node; - if (!s->nr_partial) - return NULL; - - spin_lock(&s->list_lock); /* * Search for slab on the right node */ list_for_each_entry(page, &s->partial, lru) if (likely(page_to_nid(page) == searchnode) && lock_and_del_slab(s, page)) - goto out; - - if (likely(!(flags & __GFP_THISNODE))) { - /* - * We can fall back to any other node in order to - * reduce the size of the partial list. - */ - list_for_each_entry(page, &s->partial, lru) - if (likely(lock_and_del_slab(s, page))) - goto out; - } + return NULL; - /* Nothing found */ - page = NULL; -out: - spin_unlock(&s->list_lock); - return page; +#endif + return NULL; } -#else + +/* + * Get a partial page, lock it and return it. + */ static struct page *get_partial(struct kmem_cache *s, gfp_t flags, int node) { struct page *page; @@ -280,17 +262,24 @@ return NULL; spin_lock(&s->list_lock); + + page = numa_partial(s, flags, node); + if (page) + goto out; + + if (NUMA_BUILD && !(flags & __GFP_THISNODE)) + goto out; + list_for_each_entry(page, &s->partial, lru) if (likely(lock_and_del_slab(s, page))) goto out; - /* No slab or all slabs busy */ + /* Nothing found */ page = NULL; out: spin_unlock(&s->list_lock); return page; } -#endif /* * Debugging checks @@ -402,17 +391,12 @@ { struct page *page; - if (flags & __GFP_WAIT) - local_irq_enable(); - page = allocate_slab(s, flags, node); if (!page) - goto out; + return NULL; page->offset = s->offset; - atomic_long_inc(&s->nr_slabs); - page->slab = (struct kmem_cache *)s; __SetPageSlab(page); @@ -433,10 +417,6 @@ check_free_chain(s, page); } else __SetPageSlabsingle(page); - -out: - if (flags & __GFP_WAIT) - local_irq_disable(); return page; } @@ -557,7 +537,7 @@ } #endif -static __always_inline void *__slab_alloc(struct kmem_cache *s, +static __always_inline void *allocate(struct kmem_cache *s, gfp_t gfpflags, int node) { struct active_slab *a; @@ -583,11 +563,19 @@ new_slab: a->page = get_partial(s, gfpflags, node); if (unlikely(!a->page)) { - struct page *page = new_slab(s, flags, node); + struct page *page; + + if (flags & __GFP_WAIT) + local_irq_enable(); + + page = new_slab(s, flags, node); + + if (flags & __GFP_WAIT) + local_irq_disable(); if (!page) { - local_irq_restore(flags); - return NULL; + object = NULL; + goto out; } /* @@ -595,12 +583,20 @@ * on an active list. */ if (unlikely(s->objects == 1)) { - local_irq_restore(flags); - return page_address(page); + object = page_address(page); + goto out; } + /* + * We may have reenabled interrupts during the allocation + * Verify the state of the slab. + */ a = ACTIVE_SLAB(s, smp_processor_id()); if (a->page) + /* + * Someone else already allocated a page. Drop the + * new one. + */ discard_slab(s, page); else a->page = page; @@ -624,19 +620,21 @@ a->nr_free--; a->referenced = 1; a->freelist = object[a->page->offset]; + #ifdef CONFIG_SMP if (!a->flush_active && keventd_up()) { a->flush_active = 1; schedule_delayed_work(&a->flush, 2 * HZ); } #endif +out: local_irq_restore(flags); return object; } void *kmem_cache_alloc(struct kmem_cache *s, gfp_t gfpflags) { - return __slab_alloc(s, gfpflags, -1); + return allocate(s, gfpflags, -1); } EXPORT_SYMBOL(kmem_cache_alloc); @@ -667,7 +665,7 @@ void *kmem_cache_alloc_node(struct kmem_cache *s, gfp_t gfpflags, int node) { - return __slab_alloc(s, gfpflags, node); + return allocate(s, gfpflags, node); } EXPORT_SYMBOL(kmem_cache_alloc_node); #endif @@ -864,7 +862,6 @@ return order; } -#ifdef CONFIG_NUMA /* * Boot strap slabs */ @@ -876,13 +873,37 @@ * However, be aware that deriving allocators depends on kmalloc being * functional. */ -static enum {DOWN, PARTIAL, UP } slab_state = DOWN; +static enum { DOWN, PARTIAL, UP } slab_state = DOWN; -int slab_is_available(void) { +int slab_is_available(void) +{ return slab_state == UP; } +static void alloc_active(struct kmem_cache *s, int cpu) +{ + struct active_slab *a; + +#ifdef CONFIG_NUMA + if (slab_state == DOWN) { + BUG_ON(s != ACTIVE_SLAB_SLAB); + a = early_active_slab_alloc(cpu_to_node(cpu)); + } else + a = kmem_cache_alloc_node(ACTIVE_SLAB_SLAB, + GFP_KERNEL, cpu_to_node(cpu)); + BUG_ON(!a); + s->active[cpu] = a; +#else + a = ACTIVE_SLAB(s, cpu); +#endif +#ifdef CONFIG_SMP + a->flush_active = 0; + INIT_DELAYED_WORK(&a->flush, check_flush_active); #endif + a->page = NULL; + a->slab = s; + a->referenced = 0; +} int kmem_cache_open(struct kmem_cache *s, const char *name, size_t size, @@ -944,29 +965,8 @@ if (!s->objects) goto error; - for_each_online_cpu(cpu) { - struct active_slab *a; - -#ifdef CONFIG_NUMA - if (slab_state == DOWN) { - BUG_ON(s != ACTIVE_SLAB_SLAB); - a = early_active_slab_alloc(cpu_to_node(cpu)); - } else - a = kmem_cache_alloc_node(ACTIVE_SLAB_SLAB, - GFP_KERNEL, cpu_to_node(cpu)); - s->active[cpu] = a; -#else - a = ACTIVE_SLAB(s, cpu); -#endif - - a->page = NULL; - a->slab = s; - a->referenced = 0; -#ifdef CONFIG_SMP - a->flush_active = 0; - INIT_DELAYED_WORK(&a->flush, check_flush_active); -#endif - } + for_each_online_cpu(cpu) + alloc_active(s, cpu); register_slab(s); return 1; @@ -1143,14 +1143,23 @@ return slabs_inuse; } +void release_active(struct kmem_cache *s) +{ +#ifdef CONFIG_NUMA + int cpu; + + for_each_online_cpu(cpu) { + kfree(ACTIVE_SLAB(s, cpu)); + s->active[cpu] = NULL; + } +#endif +} /* * Release all resources used by slab cache * (Use with caches setup using kmem_cache_setup) */ int kmem_cache_close(struct kmem_cache *s) { - int cpu; - if (!atomic_dec_and_test(&s->refcount)) return 0; @@ -1161,11 +1170,7 @@ return 1; unregister_slab(s); - -#ifdef CONFIG_NUMA - for_each_online_cpu(cpu) - kfree(ACTIVE_SLAB(s, cpu)); -#endif + release_active(s); return 0; } EXPORT_SYMBOL(kmem_cache_close); @@ -1295,7 +1300,7 @@ #endif create_kmalloc_cache(s, - kasprintf(flags, "kmalloc-dma-%ld", realsize), + kasprintf(flags, "kmalloc-dma-%d", realsize), realsize); kmalloc_caches_dma[index] = s; return s; @@ -1362,20 +1367,20 @@ #ifdef KMALLOC_EXTRA /* Non-power of two caches */ create_kmalloc_cache(&kmalloc_caches - [KMALLOC_SHIFT_HIGH - KMALLOC_SHIFT_LOW + 1], bootname, 96); + [KMALLOC_SHIFT_HIGH - KMALLOC_SHIFT_LOW + 1], + "kmalloc-96", 96); create_kmalloc_cache(&kmalloc_caches - [KMALLOC_SHIFT_HIGH - KMALLOC_SHIFT_LOW + 2], bootname, 192); + [KMALLOC_SHIFT_HIGH - KMALLOC_SHIFT_LOW + 2], + "kmalloc-192", 192); #endif slab_state = UP; /* We can provide the kmalloc names now that the caches are up */ - for (i = 0; i < KMALLOC_SHIFT_HIGH - KMALLOC_SHIFT_LOW - + KMALLOC_EXTRAS; - i++) + for (i = 0; i < KMALLOC_SHIFT_HIGH - KMALLOC_SHIFT_LOW; i++) kmalloc_caches[i].name = kasprintf(GFP_KERNEL, "kmalloc-%d", kmalloc_caches[i].size); - printk(KERN_INFO "Kmalloc cache initialized: Caches %d." - " Min_order %d.\n", + printk(KERN_INFO "Kmalloc cache initialized: Caches=%d" + " Min_order=%d.\n", KMALLOC_SHIFT_HIGH - KMALLOC_SHIFT_LOW + KMALLOC_EXTRAS, slab_min_order); } @@ -1420,7 +1425,7 @@ * a new slab. */ if (s->size - sz <= sizeof(void *)) { - printk(KERN_INFO "SLUB: Merging slab_cache %s size %ld" + printk(KERN_INFO "SLUB: Merging slab_cache %s size %d" " into kmalloc array size %d\n", name, size, s->size); return kmem_cache_dup(s);