--- mm/slub.c | 39 ++++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 13 deletions(-) Index: linux-2.6/mm/slub.c =================================================================== --- linux-2.6.orig/mm/slub.c 2009-10-13 16:31:43.000000000 -0500 +++ linux-2.6/mm/slub.c 2009-10-13 16:56:25.000000000 -0500 @@ -1287,6 +1287,18 @@ static void remove_partial(struct kmem_c spin_unlock(&n->list_lock); } +static void remove_if_on_partial(struct kmem_cache *s, struct page *page) +{ + struct kmem_cache_node *n = get_node(s, page_to_nid(page)); + + local_irq_save(flags); + spin_lock(&n->list_lock); + list_del(&page->lru); + n->nr_partial--; + spin_unlock(&n->list_lock); + local_irq_restore(flags); +} + /* * Lock slab and remove from the partial list. * @@ -1839,27 +1851,27 @@ static void __slab_free(struct kmem_cach { void *prior; void **object = (void *)x; - unsigned long flags; - local_irq_save(flags); stat(s, FREE_SLOWPATH); - slab_lock(page); if (unlikely(SLABDEBUG && PageSlubDebug(page))) goto debug; checks_ok: - prior = page->freelist; - set_freepointer(s, object, prior); - page->freelist = object; - page->inuse--; + do { + prior = page->freelist; + set_freepointer(s, object, prior); + } while (prior != LOCKED && cmpxchg(page->freelist, prior, object) != prior) + zero = atomic_dec_and_testzero(page->inuse); + + /* Racy */ if (unlikely(PageSlubFrozen(page))) { stat(s, FREE_FROZEN); goto out_unlock; } - if (unlikely(!page->inuse)) + if (unlikely(zero)) goto slab_empty; /* @@ -1867,13 +1879,14 @@ checks_ok: * then add it. */ if (unlikely(!prior)) { + /* Transition from full to one object free */ + local_irq_save(flags); add_partial(get_node(s, page_to_nid(page)), page, 1); + local_irq_restore(flags); stat(s, FREE_ADD_PARTIAL); } out_unlock: - slab_unlock(page); - local_irq_restore(flags); return; slab_empty: @@ -1881,11 +1894,11 @@ slab_empty: /* * Slab still on the partial list. */ - remove_partial(s, page); + local_irq_save(flags); + remove_if_on_partial_partial(s, page); + local_irq_restore(flags); stat(s, FREE_REMOVE_PARTIAL); } - slab_unlock(page); - local_irq_restore(flags); stat(s, FREE_SLAB); discard_slab(s, page); return;