--- mm/slub.c | 36 ++++++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) Index: linux-2.6/mm/slub.c =================================================================== --- linux-2.6.orig/mm/slub.c 2007-10-28 09:39:33.000000000 -0700 +++ linux-2.6/mm/slub.c 2007-10-28 09:51:39.000000000 -0700 @@ -1719,7 +1719,7 @@ EXPORT_SYMBOL(kmem_cache_alloc_node); * handling required then we can return immediately. */ static void __slab_free(struct kmem_cache *s, struct page *page, - void *x, void *addr, unsigned int offset) + void *x, void *addr, struct kmem_cache_cpu *c) { void *prior; void **object = (void *)x; @@ -1735,7 +1735,7 @@ static void __slab_free(struct kmem_cach if (unlikely(state & SLABDEBUG)) goto debug; checks_ok: - prior = object[offset] = page->freelist; + prior = object[c->offset] = page->freelist; page->freelist = object; page->inuse--; @@ -1750,8 +1750,32 @@ checks_ok: * was not on the partial list before * then add it. */ - if (unlikely(prior == page->end)) - add_partial(s, page, 0); + if (unlikely(prior == page->end)) { + unsigned long state2; + + if (c->page && !(state2 = slab_trylock(c->page))) + /* + * We have a cpu slab but could not lock it. + * The only way out is to put the page + * onto the partial list. + */ + add_partial(s, page, 0); + else { + /* + * Make the page the cpuslab. That way future + * frees from the same slab do not require taking + * a lock. + */ + if (c->page) + deactivate_slab(s, c, state2); + c->page = page; + c->freelist = object; + c->node = page_to_nid(page); + page->freelist = prior; + page->inuse = c->objects; + state |= FROZEN; + } + } out_unlock: slab_unlock(page, state); @@ -1817,7 +1841,7 @@ static void __always_inline slab_free(st * since the freelist pointers are unique per slab. */ if (unlikely(page != c->page || c->node < 0)) { - __slab_free(s, page, x, addr, c->offset); + __slab_free(s, page, x, addr, c); break; } object[c->offset] = freelist; @@ -1833,7 +1857,7 @@ static void __always_inline slab_free(st object[c->offset] = c->freelist; c->freelist = object; } else - __slab_free(s, page, x, addr, c->offset); + __slab_free(s, page, x, addr, c); local_irq_restore(flags); #endif