Index: linux-2.6/mm/slub.c =================================================================== --- linux-2.6.orig/mm/slub.c 2007-07-02 11:21:45.000000000 -0700 +++ linux-2.6/mm/slub.c 2007-07-02 13:23:23.000000000 -0700 @@ -1430,15 +1430,8 @@ goto new_slab; slab_lock(page); - /* - * Check for a slab that must be deactivated. This may occur because - * - * 1. Page locality is not right for the NUMA case. - * 2. A race has left us handling a Frozen Slab which we only - * handle in slab_alloc(). Unfreeze the frozen slab. - */ - if (unlikely(SlabFrozen(page) || - (node != -1 && page_to_nid(page) != node))) + if (unlikely(page->lockless_freelist < LOCKLESS_OFF && + node != -1 && page_to_nid(page) != node)) goto another_slab; load_freelist: object = page->freelist; @@ -1526,20 +1519,45 @@ void **object; redo: + /* + * Note: The current cpu slab is determined in a racy way since we + * do not disable preemption nor disable interrupts. So we + * cannot pass the page struct pointer determined here to + * __slab_alloc. + * + * We may switch cpus after the page has been determined. Then we + * may allocate from a remote processors cpu slab. Or we may find + * that the remote processors queue is empty and call __slab_alloc + * on a different cpu. __slab_alloc will handle all our messes. + */ page = s->cpu_slab[raw_smp_processor_id()]; - if (unlikely(!page || - page->lockless_freelist <= LOCKLESS_OFF || - (node != -1 && page_to_nid(page) != node))) - - object = __slab_alloc(s, gfpflags, node, addr); - - else { - object = page->lockless_freelist; - if (cmpxchg(&page->lockless_freelist, object, - object[page->offset]) != object) - goto redo; - } + if (unlikely(!page)) + /* No slab on the per cpu array yet */ + goto slow; + + /* Simply take the next object from the lockless freelist */ + object = page->lockless_freelist; + + if (unlikely(object <= LOCKLESS_OFF)) + /* + * Slab is fully allocated or we are not allowed + * to use lockless allocs. + */ + goto slow; + + if (unlikely(node != -1 && page_to_nid(page) != node)) + /* + * Slab is not fitting NUMA criteria + */ + goto slow; + + if (cmpxchg(&page->lockless_freelist, object, + object[page->offset]) != object) + goto redo; + return object; +slow: + return __slab_alloc(s, gfpflags, node, addr); } void *kmem_cache_alloc(struct kmem_cache *s, gfp_t gfpflags) @@ -1637,12 +1655,22 @@ redo: ll = page->lockless_freelist; - if (likely(ll != LOCKLESS_OFF)) { - object[page->offset] = ll; - if (cmpxchg(&page->lockless_freelist, ll, object) != ll) - goto redo; - } else - __slab_free(s, page, x, addr); + + if (unlikely(ll == LOCKLESS_OFF)) + /* Not allowed to use lockless operations on this slab */ + goto slow; + + /* Speculatively set up the freelist pointer */ + object[page->offset] = ll; + + /* And atomically update the lockless freelist */ + if (cmpxchg(&page->lockless_freelist, ll, object) != ll) + goto redo; + + return; + +slow: + __slab_free(s, page, x, addr); } void kmem_cache_free(struct kmem_cache *s, void *x)