--- include/linux/slub_def.h | 10 ++++---- mm/slub.c | 53 ++++++++++++++++++++++++++++++++--------------- 2 files changed, 42 insertions(+), 21 deletions(-) Index: linux-2.6.22-rc6-mm1/mm/slub.c =================================================================== --- linux-2.6.22-rc6-mm1.orig/mm/slub.c 2007-07-07 18:56:12.000000000 -0700 +++ linux-2.6.22-rc6-mm1/mm/slub.c 2007-07-07 18:58:00.000000000 -0700 @@ -1467,13 +1467,18 @@ static inline int node_match(struct kmem * we need to allocate a new slab. This is slowest path since we may sleep. */ static void *__slab_alloc(struct kmem_cache *s, - gfp_t gfpflags, int node, void *addr, struct kmem_cache_cpu *c) + gfp_t gfpflags, int node, void *addr) { void **object; struct page *new; + struct kmem_cache_cpu *c; void **freelist = NULL; + unsigned long flags; + local_irq_save(flags); + c = get_cpu_slab(s, smp_processor_id()); if (!c->page) + /* Slab was flushed */ goto new_slab; freelist = xchg(&c->freelist, NULL); @@ -1481,6 +1486,12 @@ static void *__slab_alloc(struct kmem_ca slab_lock(c->page); if (unlikely(!node_match(c, node))) goto another_slab; + + if (unlikely(freelist)) { + object = freelist; + goto out_object; + } + load_freelist: object = c->page->freelist; if (unlikely(!object)) @@ -1489,11 +1500,16 @@ load_freelist: goto debug; object = c->page->freelist; - c->freelist = object[c->offset]; c->page->inuse = s->objects; c->page->freelist = NULL; c->node = page_to_nid(c->page); +out_object: + c->freelist = object[c->offset]; slab_unlock(c->page); +out: + local_irq_restore(flags); + if (unlikely((gfpflags & __GFP_ZERO))) + memset(object, 0, c->objsize); return object; another_slab: @@ -1534,17 +1550,19 @@ new_slab: c->page = new; goto load_freelist; } + local_irq_restore(flags); return NULL; debug: - c->freelist = NULL; object = c->page->freelist; if (!alloc_debug_processing(s, c->page, object, addr)) goto another_slab; + c->freelist = NULL; c->page->inuse++; c->page->freelist = object[c->offset]; + c->node = page_to_nid(c->page); slab_unlock(c->page); - return object; + goto out; } /* @@ -1561,26 +1579,29 @@ static void __always_inline *slab_alloc( gfp_t gfpflags, int node, void *addr) { void **object; - unsigned long flags; struct kmem_cache_cpu *c; - local_irq_save(flags); - c = get_cpu_slab(s, smp_processor_id()); - if (unlikely(!c->page || !c->freelist || - !node_match(c, node))) +redo: + c = get_cpu_slab(s, raw_smp_processor_id()); + object = c->freelist; - object = __slab_alloc(s, gfpflags, node, addr, c); + if (unlikely(!object)) + goto slow; - else { - object = c->freelist; - c->freelist = object[c->offset]; - } - local_irq_restore(flags); + if (unlikely(!node_match(c, node))) + goto slow; + + if (unlikely(cmpxchg(&c->freelist, object, + object[c->offset]) != object)) + goto redo; - if (unlikely((gfpflags & __GFP_ZERO) && object)) + if (unlikely((gfpflags & __GFP_ZERO))) memset(object, 0, c->objsize); return object; + +slow: + return __slab_alloc(s, gfpflags, node, addr); } void *kmem_cache_alloc(struct kmem_cache *s, gfp_t gfpflags) Index: linux-2.6.22-rc6-mm1/include/linux/slub_def.h =================================================================== --- linux-2.6.22-rc6-mm1.orig/include/linux/slub_def.h 2007-07-07 18:56:12.000000000 -0700 +++ linux-2.6.22-rc6-mm1/include/linux/slub_def.h 2007-07-07 18:57:39.000000000 -0700 @@ -12,11 +12,11 @@ #include struct kmem_cache_cpu { - void **freelist; - struct page *page; - int node; - unsigned int offset; - unsigned int objsize; + void **freelist; /* Updated through atomic ops */ + struct page *page; /* Updated with interrupts disabled */ + int node; /* Updated with interrupts disabled */ + unsigned int offset; /* Set up on kmem_cache_create() */ + unsigned int objsize; /* Set up on kmem_cache_create() */ }; struct kmem_cache_node {