Merge branch 'slub/lockless' of git://git.kernel.org/pub/scm/linux/kernel/git/penberg...
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 30 Jul 2011 18:21:48 +0000 (08:21 -1000)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 30 Jul 2011 18:21:48 +0000 (08:21 -1000)
* 'slub/lockless' of git://git.kernel.org/pub/scm/linux/kernel/git/penberg/slab-2.6: (21 commits)
  slub: When allocating a new slab also prep the first object
  slub: disable interrupts in cmpxchg_double_slab when falling back to pagelock
  Avoid duplicate _count variables in page_struct
  Revert "SLUB: Fix build breakage in linux/mm_types.h"
  SLUB: Fix build breakage in linux/mm_types.h
  slub: slabinfo update for cmpxchg handling
  slub: Not necessary to check for empty slab on load_freelist
  slub: fast release on full slab
  slub: Add statistics for the case that the current slab does not match the node
  slub: Get rid of the another_slab label
  slub: Avoid disabling interrupts in free slowpath
  slub: Disable interrupts in free_debug processing
  slub: Invert locking and avoid slab lock
  slub: Rework allocator fastpaths
  slub: Pass kmem_cache struct to lock and freeze slab
  slub: explicit list_lock taking
  slub: Add cmpxchg_double_slab()
  mm: Rearrange struct page
  slub: Move page->frozen handling near where the page->freelist handling occurs
  slub: Do not use frozen page flag but a bit in the page counters
  ...

1  2 
include/linux/page-flags.h
include/linux/slub_def.h
mm/slub.c

@@@ -124,9 -124,6 +124,6 @@@ enum pageflags 
  
        /* SLOB */
        PG_slob_free = PG_private,
-       /* SLUB */
-       PG_slub_frozen = PG_active,
  };
  
  #ifndef __GENERATING_BOUNDS_H
   * Macros to create function definitions for page flags
   */
  #define TESTPAGEFLAG(uname, lname)                                    \
 -static inline int Page##uname(struct page *page)                      \
 +static inline int Page##uname(const struct page *page)                        \
                        { return test_bit(PG_##lname, &page->flags); }
  
  #define SETPAGEFLAG(uname, lname)                                     \
@@@ -173,7 -170,7 +170,7 @@@ static inline int __TestClearPage##unam
        __SETPAGEFLAG(uname, lname)  __CLEARPAGEFLAG(uname, lname)
  
  #define PAGEFLAG_FALSE(uname)                                                 \
 -static inline int Page##uname(struct page *page)                      \
 +static inline int Page##uname(const struct page *page)                        \
                        { return 0; }
  
  #define TESTSCFLAG(uname, lname)                                      \
@@@ -212,8 -209,6 +209,6 @@@ PAGEFLAG(SwapBacked, swapbacked) __CLEA
  
  __PAGEFLAG(SlobFree, slob_free)
  
- __PAGEFLAG(SlubFrozen, slub_frozen)
  /*
   * Private page markings that may be used by the filesystem that owns the page
   * for its own purposes.
diff --combined include/linux/slub_def.h
@@@ -24,6 -24,7 +24,7 @@@ enum stat_item 
        ALLOC_FROM_PARTIAL,     /* Cpu slab acquired from partial list */
        ALLOC_SLAB,             /* Cpu slab acquired from page allocator */
        ALLOC_REFILL,           /* Refill cpu slab from slab freelist */
+       ALLOC_NODE_MISMATCH,    /* Switching cpu slab */
        FREE_SLAB,              /* Slab freed to the page allocator */
        CPUSLAB_FLUSH,          /* Abandoning of the cpu slab */
        DEACTIVATE_FULL,        /* Cpu slab was full when deactivated */
        DEACTIVATE_TO_HEAD,     /* Cpu slab was moved to the head of partials */
        DEACTIVATE_TO_TAIL,     /* Cpu slab was moved to the tail of partials */
        DEACTIVATE_REMOTE_FREES,/* Slab contained remotely freed objects */
+       DEACTIVATE_BYPASS,      /* Implicit deactivation */
        ORDER_FALLBACK,         /* Number of times fallback was necessary */
        CMPXCHG_DOUBLE_CPU_FAIL,/* Failure of this_cpu_cmpxchg_double */
+       CMPXCHG_DOUBLE_FAIL,    /* Number of times that cmpxchg double did not match */
        NR_SLUB_STAT_ITEMS };
  
  struct kmem_cache_cpu {
@@@ -113,6 -116,16 +116,6 @@@ struct kmem_cache 
  
  #define KMALLOC_SHIFT_LOW ilog2(KMALLOC_MIN_SIZE)
  
 -#ifdef ARCH_DMA_MINALIGN
 -#define ARCH_KMALLOC_MINALIGN ARCH_DMA_MINALIGN
 -#else
 -#define ARCH_KMALLOC_MINALIGN __alignof__(unsigned long long)
 -#endif
 -
 -#ifndef ARCH_SLAB_MINALIGN
 -#define ARCH_SLAB_MINALIGN __alignof__(unsigned long long)
 -#endif
 -
  /*
   * Maximum kmalloc object size handled by SLUB. Larger object allocations
   * are passed through to the page allocator. The page allocator "fastpath"
@@@ -218,19 -231,6 +221,19 @@@ kmalloc_order(size_t size, gfp_t flags
        return ret;
  }
  
 +/**
 + * Calling this on allocated memory will check that the memory
 + * is expected to be in use, and print warnings if not.
 + */
 +#ifdef CONFIG_SLUB_DEBUG
 +extern bool verify_mem_not_deleted(const void *x);
 +#else
 +static inline bool verify_mem_not_deleted(const void *x)
 +{
 +      return true;
 +}
 +#endif
 +
  #ifdef CONFIG_TRACING
  extern void *
  kmem_cache_alloc_trace(struct kmem_cache *s, gfp_t gfpflags, size_t size);
diff --combined mm/slub.c
+++ b/mm/slub.c
@@@ -2,10 -2,11 +2,11 @@@
   * SLUB: A slab allocator that limits cache line use instead of queuing
   * objects in per cpu and per node lists.
   *
-  * The allocator synchronizes using per slab locks and only
-  * uses a centralized lock to manage a pool of partial slabs.
+  * The allocator synchronizes using per slab locks or atomic operatios
+  * and only uses a centralized lock to manage a pool of partial slabs.
   *
   * (C) 2007 SGI, Christoph Lameter
+  * (C) 2011 Linux Foundation, Christoph Lameter
   */
  
  #include <linux/mm.h>
  #include <linux/memory.h>
  #include <linux/math64.h>
  #include <linux/fault-inject.h>
 +#include <linux/stacktrace.h>
  
  #include <trace/events/kmem.h>
  
  /*
   * Lock order:
-  *   1. slab_lock(page)
-  *   2. slab->list_lock
+  *   1. slub_lock (Global Semaphore)
+  *   2. node->list_lock
+  *   3. slab_lock(page) (Only on some arches and for debugging)
   *
-  *   The slab_lock protects operations on the object of a particular
-  *   slab and its metadata in the page struct. If the slab lock
-  *   has been taken then no allocations nor frees can be performed
-  *   on the objects in the slab nor can the slab be added or removed
-  *   from the partial or full lists since this would mean modifying
-  *   the page_struct of the slab.
+  *   slub_lock
+  *
+  *   The role of the slub_lock is to protect the list of all the slabs
+  *   and to synchronize major metadata changes to slab cache structures.
+  *
+  *   The slab_lock is only used for debugging and on arches that do not
+  *   have the ability to do a cmpxchg_double. It only protects the second
+  *   double word in the page struct. Meaning
+  *    A. page->freelist       -> List of object free in a page
+  *    B. page->counters       -> Counters of objects
+  *    C. page->frozen         -> frozen state
+  *
+  *   If a slab is frozen then it is exempt from list management. It is not
+  *   on any list. The processor that froze the slab is the one who can
+  *   perform list operations on the page. Other processors may put objects
+  *   onto the freelist but the processor that froze the slab is the only
+  *   one that can retrieve the objects from the page's freelist.
   *
   *   The list_lock protects the partial and full list on each node and
   *   the partial slab counter. If taken then no new slabs may be added or
   *   slabs, operations can continue without any centralized lock. F.e.
   *   allocating a long series of objects that fill up slabs does not require
   *   the list lock.
-  *
-  *   The lock order is sometimes inverted when we are trying to get a slab
-  *   off a list. We take the list_lock and then look for a page on the list
-  *   to use. While we do that objects in the slabs may be freed. We can
-  *   only operate on the slab if we have also taken the slab_lock. So we use
-  *   a slab_trylock() on the slab. If trylock was successful then no frees
-  *   can occur anymore and we can use the slab for allocations etc. If the
-  *   slab_trylock() does not succeed then frees are in progress in the slab and
-  *   we must stay away from it for a while since we may cause a bouncing
-  *   cacheline if we try to acquire the lock. So go onto the next slab.
-  *   If all pages are busy then we may allocate a new slab instead of reusing
-  *   a partial slab. A new slab has no one operating on it and thus there is
-  *   no danger of cacheline contention.
-  *
   *   Interrupts are disabled during allocation and deallocation in order to
   *   make the slab allocator safe to use in the context of an irq. In addition
   *   interrupts are disabled to ensure that the processor does not change
@@@ -132,6 -130,9 +131,9 @@@ static inline int kmem_cache_debug(stru
  /* Enable to test recovery from slab corruption on boot */
  #undef SLUB_RESILIENCY_TEST
  
+ /* Enable to log cmpxchg failures */
+ #undef SLUB_DEBUG_CMPXCHG
  /*
   * Mininum number of partial slabs. These will be left on the partial
   * lists even if they are empty. kmem_cache_shrink may reclaim them.
  
  #define OO_SHIFT      16
  #define OO_MASK               ((1 << OO_SHIFT) - 1)
- #define MAX_OBJS_PER_PAGE     65535 /* since page.objects is u16 */
+ #define MAX_OBJS_PER_PAGE     32767 /* since page.objects is u15 */
  
  /* Internal SLUB flags */
  #define __OBJECT_POISON               0x80000000UL /* Poison object */
+ #define __CMPXCHG_DOUBLE      0x40000000UL /* Use cmpxchg_double */
  
  static int kmem_size = sizeof(struct kmem_cache);
  
@@@ -192,12 -194,8 +195,12 @@@ static LIST_HEAD(slab_caches)
  /*
   * Tracking user of a slab.
   */
 +#define TRACK_ADDRS_COUNT 16
  struct track {
        unsigned long addr;     /* Called from address */
 +#ifdef CONFIG_STACKTRACE
 +      unsigned long addrs[TRACK_ADDRS_COUNT]; /* Called from address */
 +#endif
        int cpu;                /* Was running on cpu */
        int pid;                /* Pid context */
        unsigned long when;     /* When did the operation occur */
@@@ -343,11 -341,99 +346,99 @@@ static inline int oo_objects(struct kme
        return x.x & OO_MASK;
  }
  
+ /*
+  * Per slab locking using the pagelock
+  */
+ static __always_inline void slab_lock(struct page *page)
+ {
+       bit_spin_lock(PG_locked, &page->flags);
+ }
+ static __always_inline void slab_unlock(struct page *page)
+ {
+       __bit_spin_unlock(PG_locked, &page->flags);
+ }
+ /* Interrupts must be disabled (for the fallback code to work right) */
+ static inline bool __cmpxchg_double_slab(struct kmem_cache *s, struct page *page,
+               void *freelist_old, unsigned long counters_old,
+               void *freelist_new, unsigned long counters_new,
+               const char *n)
+ {
+       VM_BUG_ON(!irqs_disabled());
+ #ifdef CONFIG_CMPXCHG_DOUBLE
+       if (s->flags & __CMPXCHG_DOUBLE) {
+               if (cmpxchg_double(&page->freelist,
+                       freelist_old, counters_old,
+                       freelist_new, counters_new))
+               return 1;
+       } else
+ #endif
+       {
+               slab_lock(page);
+               if (page->freelist == freelist_old && page->counters == counters_old) {
+                       page->freelist = freelist_new;
+                       page->counters = counters_new;
+                       slab_unlock(page);
+                       return 1;
+               }
+               slab_unlock(page);
+       }
+       cpu_relax();
+       stat(s, CMPXCHG_DOUBLE_FAIL);
+ #ifdef SLUB_DEBUG_CMPXCHG
+       printk(KERN_INFO "%s %s: cmpxchg double redo ", n, s->name);
+ #endif
+       return 0;
+ }
+ static inline bool cmpxchg_double_slab(struct kmem_cache *s, struct page *page,
+               void *freelist_old, unsigned long counters_old,
+               void *freelist_new, unsigned long counters_new,
+               const char *n)
+ {
+ #ifdef CONFIG_CMPXCHG_DOUBLE
+       if (s->flags & __CMPXCHG_DOUBLE) {
+               if (cmpxchg_double(&page->freelist,
+                       freelist_old, counters_old,
+                       freelist_new, counters_new))
+               return 1;
+       } else
+ #endif
+       {
+               unsigned long flags;
+               local_irq_save(flags);
+               slab_lock(page);
+               if (page->freelist == freelist_old && page->counters == counters_old) {
+                       page->freelist = freelist_new;
+                       page->counters = counters_new;
+                       slab_unlock(page);
+                       local_irq_restore(flags);
+                       return 1;
+               }
+               slab_unlock(page);
+               local_irq_restore(flags);
+       }
+       cpu_relax();
+       stat(s, CMPXCHG_DOUBLE_FAIL);
+ #ifdef SLUB_DEBUG_CMPXCHG
+       printk(KERN_INFO "%s %s: cmpxchg double redo ", n, s->name);
+ #endif
+       return 0;
+ }
  #ifdef CONFIG_SLUB_DEBUG
  /*
   * Determine a map of object in use on a page.
   *
-  * Slab lock or node listlock must be held to guarantee that the page does
+  * Node listlock must be held to guarantee that the page does
   * not vanish from under us.
   */
  static void get_map(struct kmem_cache *s, struct page *page, unsigned long *map)
@@@ -425,24 -511,6 +516,24 @@@ static void set_track(struct kmem_cach
        struct track *p = get_track(s, object, alloc);
  
        if (addr) {
 +#ifdef CONFIG_STACKTRACE
 +              struct stack_trace trace;
 +              int i;
 +
 +              trace.nr_entries = 0;
 +              trace.max_entries = TRACK_ADDRS_COUNT;
 +              trace.entries = p->addrs;
 +              trace.skip = 3;
 +              save_stack_trace(&trace);
 +
 +              /* See rant in lockdep.c */
 +              if (trace.nr_entries != 0 &&
 +                  trace.entries[trace.nr_entries - 1] == ULONG_MAX)
 +                      trace.nr_entries--;
 +
 +              for (i = trace.nr_entries; i < TRACK_ADDRS_COUNT; i++)
 +                      p->addrs[i] = 0;
 +#endif
                p->addr = addr;
                p->cpu = smp_processor_id();
                p->pid = current->pid;
@@@ -467,16 -535,6 +558,16 @@@ static void print_track(const char *s, 
  
        printk(KERN_ERR "INFO: %s in %pS age=%lu cpu=%u pid=%d\n",
                s, (void *)t->addr, jiffies - t->when, t->cpu, t->pid);
 +#ifdef CONFIG_STACKTRACE
 +      {
 +              int i;
 +              for (i = 0; i < TRACK_ADDRS_COUNT; i++)
 +                      if (t->addrs[i])
 +                              printk(KERN_ERR "\t%pS\n", (void *)t->addrs[i]);
 +                      else
 +                              break;
 +      }
 +#endif
  }
  
  static void print_tracking(struct kmem_cache *s, void *object)
@@@ -590,10 -648,10 +681,10 @@@ static void init_object(struct kmem_cac
                memset(p + s->objsize, val, s->inuse - s->objsize);
  }
  
 -static u8 *check_bytes(u8 *start, unsigned int value, unsigned int bytes)
 +static u8 *check_bytes8(u8 *start, u8 value, unsigned int bytes)
  {
        while (bytes) {
 -              if (*start != (u8)value)
 +              if (*start != value)
                        return start;
                start++;
                bytes--;
        return NULL;
  }
  
 +static u8 *check_bytes(u8 *start, u8 value, unsigned int bytes)
 +{
 +      u64 value64;
 +      unsigned int words, prefix;
 +
 +      if (bytes <= 16)
 +              return check_bytes8(start, value, bytes);
 +
 +      value64 = value | value << 8 | value << 16 | value << 24;
 +      value64 = value64 | value64 << 32;
 +      prefix = 8 - ((unsigned long)start) % 8;
 +
 +      if (prefix) {
 +              u8 *r = check_bytes8(start, value, prefix);
 +              if (r)
 +                      return r;
 +              start += prefix;
 +              bytes -= prefix;
 +      }
 +
 +      words = bytes / 8;
 +
 +      while (words) {
 +              if (*(u64 *)start != value64)
 +                      return check_bytes8(start, value, 8);
 +              start += 8;
 +              words--;
 +      }
 +
 +      return check_bytes8(start, value, bytes % 8);
 +}
 +
  static void restore_bytes(struct kmem_cache *s, char *message, u8 data,
                                                void *from, void *to)
  {
@@@ -838,10 -864,11 +929,11 @@@ static int check_slab(struct kmem_cach
  static int on_freelist(struct kmem_cache *s, struct page *page, void *search)
  {
        int nr = 0;
-       void *fp = page->freelist;
+       void *fp;
        void *object = NULL;
        unsigned long max_objects;
  
+       fp = page->freelist;
        while (fp && nr <= page->objects) {
                if (fp == search)
                        return 1;
@@@ -946,26 -973,27 +1038,27 @@@ static inline void slab_free_hook(struc
  
  /*
   * Tracking of fully allocated slabs for debugging purposes.
+  *
+  * list_lock must be held.
   */
- static void add_full(struct kmem_cache_node *n, struct page *page)
+ static void add_full(struct kmem_cache *s,
+       struct kmem_cache_node *n, struct page *page)
  {
-       spin_lock(&n->list_lock);
+       if (!(s->flags & SLAB_STORE_USER))
+               return;
        list_add(&page->lru, &n->full);
-       spin_unlock(&n->list_lock);
  }
  
+ /*
+  * list_lock must be held.
+  */
  static void remove_full(struct kmem_cache *s, struct page *page)
  {
-       struct kmem_cache_node *n;
        if (!(s->flags & SLAB_STORE_USER))
                return;
  
-       n = get_node(s, page_to_nid(page));
-       spin_lock(&n->list_lock);
        list_del(&page->lru);
-       spin_unlock(&n->list_lock);
  }
  
  /* Tracking of the number of slabs for debugging purposes */
@@@ -1021,11 -1049,6 +1114,6 @@@ static noinline int alloc_debug_process
        if (!check_slab(s, page))
                goto bad;
  
-       if (!on_freelist(s, page, object)) {
-               object_err(s, page, object, "Object already allocated");
-               goto bad;
-       }
        if (!check_valid_pointer(s, page, object)) {
                object_err(s, page, object, "Freelist Pointer check fails");
                goto bad;
  static noinline int free_debug_processing(struct kmem_cache *s,
                 struct page *page, void *object, unsigned long addr)
  {
+       unsigned long flags;
+       int rc = 0;
+       local_irq_save(flags);
+       slab_lock(page);
        if (!check_slab(s, page))
                goto fail;
  
        }
  
        if (!check_object(s, page, object, SLUB_RED_ACTIVE))
-               return 0;
+               goto out;
  
        if (unlikely(s != page->slab)) {
                if (!PageSlab(page)) {
                goto fail;
        }
  
-       /* Special debug activities for freeing objects */
-       if (!PageSlubFrozen(page) && !page->freelist)
-               remove_full(s, page);
        if (s->flags & SLAB_STORE_USER)
                set_track(s, object, TRACK_FREE, addr);
        trace(s, page, object, 0);
        init_object(s, object, SLUB_RED_INACTIVE);
-       return 1;
+       rc = 1;
+ out:
+       slab_unlock(page);
+       local_irq_restore(flags);
+       return rc;
  
  fail:
        slab_fix(s, "Object at 0x%p not freed", object);
-       return 0;
+       goto out;
  }
  
  static int __init setup_slub_debug(char *str)
@@@ -1200,7 -1230,9 +1295,9 @@@ static inline int slab_pad_check(struc
                        { return 1; }
  static inline int check_object(struct kmem_cache *s, struct page *page,
                        void *object, u8 val) { return 1; }
- static inline void add_full(struct kmem_cache_node *n, struct page *page) {}
+ static inline void add_full(struct kmem_cache *s, struct kmem_cache_node *n,
+                                       struct page *page) {}
+ static inline void remove_full(struct kmem_cache *s, struct page *page) {}
  static inline unsigned long kmem_cache_flags(unsigned long objsize,
        unsigned long flags, const char *name,
        void (*ctor)(void *))
@@@ -1252,6 -1284,11 +1349,11 @@@ static struct page *allocate_slab(struc
        struct kmem_cache_order_objects oo = s->oo;
        gfp_t alloc_gfp;
  
+       flags &= gfp_allowed_mask;
+       if (flags & __GFP_WAIT)
+               local_irq_enable();
        flags |= s->allocflags;
  
        /*
                 * Try a lower order alloc if possible
                 */
                page = alloc_slab_page(flags, node, oo);
-               if (!page)
-                       return NULL;
  
-               stat(s, ORDER_FALLBACK);
+               if (page)
+                       stat(s, ORDER_FALLBACK);
        }
  
+       if (flags & __GFP_WAIT)
+               local_irq_disable();
+       if (!page)
+               return NULL;
        if (kmemcheck_enabled
                && !(s->flags & (SLAB_NOTRACK | DEBUG_DEFAULT_FLAGS))) {
                int pages = 1 << oo_order(oo);
@@@ -1341,6 -1383,7 +1448,7 @@@ static struct page *new_slab(struct kme
  
        page->freelist = start;
        page->inuse = 0;
+       page->frozen = 1;
  out:
        return page;
  }
@@@ -1418,77 -1461,87 +1526,87 @@@ static void discard_slab(struct kmem_ca
  }
  
  /*
-  * Per slab locking using the pagelock
-  */
- static __always_inline void slab_lock(struct page *page)
- {
-       bit_spin_lock(PG_locked, &page->flags);
- }
- static __always_inline void slab_unlock(struct page *page)
- {
-       __bit_spin_unlock(PG_locked, &page->flags);
- }
- static __always_inline int slab_trylock(struct page *page)
- {
-       int rc = 1;
-       rc = bit_spin_trylock(PG_locked, &page->flags);
-       return rc;
- }
- /*
-  * Management of partially allocated slabs
+  * Management of partially allocated slabs.
+  *
+  * list_lock must be held.
   */
- static void add_partial(struct kmem_cache_node *n,
+ static inline void add_partial(struct kmem_cache_node *n,
                                struct page *page, int tail)
  {
-       spin_lock(&n->list_lock);
        n->nr_partial++;
        if (tail)
                list_add_tail(&page->lru, &n->partial);
        else
                list_add(&page->lru, &n->partial);
-       spin_unlock(&n->list_lock);
  }
  
- static inline void __remove_partial(struct kmem_cache_node *n,
+ /*
+  * list_lock must be held.
+  */
+ static inline void remove_partial(struct kmem_cache_node *n,
                                        struct page *page)
  {
        list_del(&page->lru);
        n->nr_partial--;
  }
  
- static void remove_partial(struct kmem_cache *s, struct page *page)
- {
-       struct kmem_cache_node *n = get_node(s, page_to_nid(page));
-       spin_lock(&n->list_lock);
-       __remove_partial(n, page);
-       spin_unlock(&n->list_lock);
- }
  /*
-  * Lock slab and remove from the partial list.
+  * Lock slab, remove from the partial list and put the object into the
+  * per cpu freelist.
   *
   * Must hold list_lock.
   */
- static inline int lock_and_freeze_slab(struct kmem_cache_node *n,
-                                                       struct page *page)
+ static inline int acquire_slab(struct kmem_cache *s,
+               struct kmem_cache_node *n, struct page *page)
  {
-       if (slab_trylock(page)) {
-               __remove_partial(n, page);
-               __SetPageSlubFrozen(page);
+       void *freelist;
+       unsigned long counters;
+       struct page new;
+       /*
+        * Zap the freelist and set the frozen bit.
+        * The old freelist is the list of objects for the
+        * per cpu allocation list.
+        */
+       do {
+               freelist = page->freelist;
+               counters = page->counters;
+               new.counters = counters;
+               new.inuse = page->objects;
+               VM_BUG_ON(new.frozen);
+               new.frozen = 1;
+       } while (!__cmpxchg_double_slab(s, page,
+                       freelist, counters,
+                       NULL, new.counters,
+                       "lock and freeze"));
+       remove_partial(n, page);
+       if (freelist) {
+               /* Populate the per cpu freelist */
+               this_cpu_write(s->cpu_slab->freelist, freelist);
+               this_cpu_write(s->cpu_slab->page, page);
+               this_cpu_write(s->cpu_slab->node, page_to_nid(page));
                return 1;
+       } else {
+               /*
+                * Slab page came from the wrong list. No object to allocate
+                * from. Put it onto the correct list and continue partial
+                * scan.
+                */
+               printk(KERN_ERR "SLUB: %s : Page without available objects on"
+                       " partial list\n", s->name);
+               return 0;
        }
-       return 0;
  }
  
  /*
   * Try to allocate a partial slab from a specific node.
   */
- static struct page *get_partial_node(struct kmem_cache_node *n)
+ static struct page *get_partial_node(struct kmem_cache *s,
+                                       struct kmem_cache_node *n)
  {
        struct page *page;
  
  
        spin_lock(&n->list_lock);
        list_for_each_entry(page, &n->partial, lru)
-               if (lock_and_freeze_slab(n, page))
+               if (acquire_slab(s, n, page))
                        goto out;
        page = NULL;
  out:
@@@ -1554,7 -1607,7 +1672,7 @@@ static struct page *get_any_partial(str
  
                if (n && cpuset_zone_allowed_hardwall(zone, flags) &&
                                n->nr_partial > s->min_partial) {
-                       page = get_partial_node(n);
+                       page = get_partial_node(s, n);
                        if (page) {
                                put_mems_allowed();
                                return page;
@@@ -1574,60 -1627,13 +1692,13 @@@ static struct page *get_partial(struct 
        struct page *page;
        int searchnode = (node == NUMA_NO_NODE) ? numa_node_id() : node;
  
-       page = get_partial_node(get_node(s, searchnode));
+       page = get_partial_node(s, get_node(s, searchnode));
        if (page || node != NUMA_NO_NODE)
                return page;
  
        return get_any_partial(s, flags);
  }
  
- /*
-  * Move a page back to the lists.
-  *
-  * Must be called with the slab lock held.
-  *
-  * On exit the slab lock will have been dropped.
-  */
- static void unfreeze_slab(struct kmem_cache *s, struct page *page, int tail)
-       __releases(bitlock)
- {
-       struct kmem_cache_node *n = get_node(s, page_to_nid(page));
-       __ClearPageSlubFrozen(page);
-       if (page->inuse) {
-               if (page->freelist) {
-                       add_partial(n, page, tail);
-                       stat(s, tail ? DEACTIVATE_TO_TAIL : DEACTIVATE_TO_HEAD);
-               } else {
-                       stat(s, DEACTIVATE_FULL);
-                       if (kmem_cache_debug(s) && (s->flags & SLAB_STORE_USER))
-                               add_full(n, page);
-               }
-               slab_unlock(page);
-       } else {
-               stat(s, DEACTIVATE_EMPTY);
-               if (n->nr_partial < s->min_partial) {
-                       /*
-                        * Adding an empty slab to the partial slabs in order
-                        * to avoid page allocator overhead. This slab needs
-                        * to come after the other slabs with objects in
-                        * so that the others get filled first. That way the
-                        * size of the partial list stays small.
-                        *
-                        * kmem_cache_shrink can reclaim any empty slabs from
-                        * the partial list.
-                        */
-                       add_partial(n, page, 1);
-                       slab_unlock(page);
-               } else {
-                       slab_unlock(page);
-                       stat(s, FREE_SLAB);
-                       discard_slab(s, page);
-               }
-       }
- }
  #ifdef CONFIG_PREEMPT
  /*
   * Calculate the next globally unique transaction for disambiguiation
@@@ -1694,45 -1700,164 +1765,164 @@@ void init_kmem_cache_cpus(struct kmem_c
        for_each_possible_cpu(cpu)
                per_cpu_ptr(s->cpu_slab, cpu)->tid = init_tid(cpu);
  }
+ /*
+  * Remove the cpu slab
+  */
  /*
   * Remove the cpu slab
   */
  static void deactivate_slab(struct kmem_cache *s, struct kmem_cache_cpu *c)
-       __releases(bitlock)
  {
+       enum slab_modes { M_NONE, M_PARTIAL, M_FULL, M_FREE };
        struct page *page = c->page;
-       int tail = 1;
-       if (page->freelist)
+       struct kmem_cache_node *n = get_node(s, page_to_nid(page));
+       int lock = 0;
+       enum slab_modes l = M_NONE, m = M_NONE;
+       void *freelist;
+       void *nextfree;
+       int tail = 0;
+       struct page new;
+       struct page old;
+       if (page->freelist) {
                stat(s, DEACTIVATE_REMOTE_FREES);
+               tail = 1;
+       }
+       c->tid = next_tid(c->tid);
+       c->page = NULL;
+       freelist = c->freelist;
+       c->freelist = NULL;
+       /*
+        * Stage one: Free all available per cpu objects back
+        * to the page freelist while it is still frozen. Leave the
+        * last one.
+        *
+        * There is no need to take the list->lock because the page
+        * is still frozen.
+        */
+       while (freelist && (nextfree = get_freepointer(s, freelist))) {
+               void *prior;
+               unsigned long counters;
+               do {
+                       prior = page->freelist;
+                       counters = page->counters;
+                       set_freepointer(s, freelist, prior);
+                       new.counters = counters;
+                       new.inuse--;
+                       VM_BUG_ON(!new.frozen);
+               } while (!__cmpxchg_double_slab(s, page,
+                       prior, counters,
+                       freelist, new.counters,
+                       "drain percpu freelist"));
+               freelist = nextfree;
+       }
        /*
-        * Merge cpu freelist into slab freelist. Typically we get here
-        * because both freelists are empty. So this is unlikely
-        * to occur.
+        * Stage two: Ensure that the page is unfrozen while the
+        * list presence reflects the actual number of objects
+        * during unfreeze.
+        *
+        * We setup the list membership and then perform a cmpxchg
+        * with the count. If there is a mismatch then the page
+        * is not unfrozen but the page is on the wrong list.
+        *
+        * Then we restart the process which may have to remove
+        * the page from the list that we just put it on again
+        * because the number of objects in the slab may have
+        * changed.
         */
-       while (unlikely(c->freelist)) {
-               void **object;
+ redo:
  
-               tail = 0;       /* Hot objects. Put the slab first */
+       old.freelist = page->freelist;
+       old.counters = page->counters;
+       VM_BUG_ON(!old.frozen);
  
-               /* Retrieve object from cpu_freelist */
-               object = c->freelist;
-               c->freelist = get_freepointer(s, c->freelist);
+       /* Determine target state of the slab */
+       new.counters = old.counters;
+       if (freelist) {
+               new.inuse--;
+               set_freepointer(s, freelist, old.freelist);
+               new.freelist = freelist;
+       } else
+               new.freelist = old.freelist;
+       new.frozen = 0;
+       if (!new.inuse && n->nr_partial < s->min_partial)
+               m = M_FREE;
+       else if (new.freelist) {
+               m = M_PARTIAL;
+               if (!lock) {
+                       lock = 1;
+                       /*
+                        * Taking the spinlock removes the possiblity
+                        * that acquire_slab() will see a slab page that
+                        * is frozen
+                        */
+                       spin_lock(&n->list_lock);
+               }
+       } else {
+               m = M_FULL;
+               if (kmem_cache_debug(s) && !lock) {
+                       lock = 1;
+                       /*
+                        * This also ensures that the scanning of full
+                        * slabs from diagnostic functions will not see
+                        * any frozen slabs.
+                        */
+                       spin_lock(&n->list_lock);
+               }
+       }
+       if (l != m) {
+               if (l == M_PARTIAL)
+                       remove_partial(n, page);
+               else if (l == M_FULL)
+                       remove_full(s, page);
+               if (m == M_PARTIAL) {
+                       add_partial(n, page, tail);
+                       stat(s, tail ? DEACTIVATE_TO_TAIL : DEACTIVATE_TO_HEAD);
+               } else if (m == M_FULL) {
  
-               /* And put onto the regular freelist */
-               set_freepointer(s, object, page->freelist);
-               page->freelist = object;
-               page->inuse--;
+                       stat(s, DEACTIVATE_FULL);
+                       add_full(s, n, page);
+               }
+       }
+       l = m;
+       if (!__cmpxchg_double_slab(s, page,
+                               old.freelist, old.counters,
+                               new.freelist, new.counters,
+                               "unfreezing slab"))
+               goto redo;
+       if (lock)
+               spin_unlock(&n->list_lock);
+       if (m == M_FREE) {
+               stat(s, DEACTIVATE_EMPTY);
+               discard_slab(s, page);
+               stat(s, FREE_SLAB);
        }
-       c->page = NULL;
-       c->tid = next_tid(c->tid);
-       unfreeze_slab(s, page, tail);
  }
  
  static inline void flush_slab(struct kmem_cache *s, struct kmem_cache_cpu *c)
  {
        stat(s, CPUSLAB_FLUSH);
-       slab_lock(c->page);
        deactivate_slab(s, c);
  }
  
@@@ -1861,6 -1986,8 +2051,8 @@@ static void *__slab_alloc(struct kmem_c
        void **object;
        struct page *page;
        unsigned long flags;
+       struct page new;
+       unsigned long counters;
  
        local_irq_save(flags);
  #ifdef CONFIG_PREEMPT
        if (!page)
                goto new_slab;
  
-       slab_lock(page);
-       if (unlikely(!node_match(c, node)))
-               goto another_slab;
+       if (unlikely(!node_match(c, node))) {
+               stat(s, ALLOC_NODE_MISMATCH);
+               deactivate_slab(s, c);
+               goto new_slab;
+       }
+       stat(s, ALLOC_SLOWPATH);
+       do {
+               object = page->freelist;
+               counters = page->counters;
+               new.counters = counters;
+               VM_BUG_ON(!new.frozen);
+               /*
+                * If there is no object left then we use this loop to
+                * deactivate the slab which is simple since no objects
+                * are left in the slab and therefore we do not need to
+                * put the page back onto the partial list.
+                *
+                * If there are objects left then we retrieve them
+                * and use them to refill the per cpu queue.
+               */
+               new.inuse = page->objects;
+               new.frozen = object != NULL;
+       } while (!__cmpxchg_double_slab(s, page,
+                       object, counters,
+                       NULL, new.counters,
+                       "__slab_alloc"));
+       if (unlikely(!object)) {
+               c->page = NULL;
+               stat(s, DEACTIVATE_BYPASS);
+               goto new_slab;
+       }
  
        stat(s, ALLOC_REFILL);
  
  load_freelist:
-       object = page->freelist;
-       if (unlikely(!object))
-               goto another_slab;
-       if (kmem_cache_debug(s))
-               goto debug;
+       VM_BUG_ON(!page->frozen);
        c->freelist = get_freepointer(s, object);
-       page->inuse = page->objects;
-       page->freelist = NULL;
-       slab_unlock(page);
        c->tid = next_tid(c->tid);
        local_irq_restore(flags);
-       stat(s, ALLOC_SLOWPATH);
        return object;
  
- another_slab:
-       deactivate_slab(s, c);
  new_slab:
        page = get_partial(s, gfpflags, node);
        if (page) {
                stat(s, ALLOC_FROM_PARTIAL);
-               c->node = page_to_nid(page);
-               c->page = page;
+               object = c->freelist;
+               if (kmem_cache_debug(s))
+                       goto debug;
                goto load_freelist;
        }
  
-       gfpflags &= gfp_allowed_mask;
-       if (gfpflags & __GFP_WAIT)
-               local_irq_enable();
        page = new_slab(s, gfpflags, node);
  
-       if (gfpflags & __GFP_WAIT)
-               local_irq_disable();
        if (page) {
                c = __this_cpu_ptr(s->cpu_slab);
-               stat(s, ALLOC_SLAB);
                if (c->page)
                        flush_slab(s, c);
  
-               slab_lock(page);
-               __SetPageSlubFrozen(page);
+               /*
+                * No other reference to the page yet so we can
+                * muck around with it freely without cmpxchg
+                */
+               object = page->freelist;
+               page->freelist = NULL;
+               page->inuse = page->objects;
+               stat(s, ALLOC_SLAB);
                c->node = page_to_nid(page);
                c->page = page;
+               if (kmem_cache_debug(s))
+                       goto debug;
                goto load_freelist;
        }
        if (!(gfpflags & __GFP_NOWARN) && printk_ratelimit())
                slab_out_of_memory(s, gfpflags, node);
        local_irq_restore(flags);
        return NULL;
  debug:
-       if (!alloc_debug_processing(s, page, object, addr))
-               goto another_slab;
+       if (!object || !alloc_debug_processing(s, page, object, addr))
+               goto new_slab;
  
-       page->inuse++;
-       page->freelist = get_freepointer(s, object);
+       c->freelist = get_freepointer(s, object);
        deactivate_slab(s, c);
        c->page = NULL;
        c->node = NUMA_NO_NODE;
@@@ -2096,40 -2248,75 +2313,75 @@@ static void __slab_free(struct kmem_cac
  {
        void *prior;
        void **object = (void *)x;
-       unsigned long flags;
+       int was_frozen;
+       int inuse;
+       struct page new;
+       unsigned long counters;
+       struct kmem_cache_node *n = NULL;
+       unsigned long uninitialized_var(flags);
  
-       local_irq_save(flags);
-       slab_lock(page);
        stat(s, FREE_SLOWPATH);
  
        if (kmem_cache_debug(s) && !free_debug_processing(s, page, x, addr))
-               goto out_unlock;
+               return;
  
-       prior = page->freelist;
-       set_freepointer(s, object, prior);
-       page->freelist = object;
-       page->inuse--;
+       do {
+               prior = page->freelist;
+               counters = page->counters;
+               set_freepointer(s, object, prior);
+               new.counters = counters;
+               was_frozen = new.frozen;
+               new.inuse--;
+               if ((!new.inuse || !prior) && !was_frozen && !n) {
+                         n = get_node(s, page_to_nid(page));
+                       /*
+                        * Speculatively acquire the list_lock.
+                        * If the cmpxchg does not succeed then we may
+                        * drop the list_lock without any processing.
+                        *
+                        * Otherwise the list_lock will synchronize with
+                        * other processors updating the list of slabs.
+                        */
+                         spin_lock_irqsave(&n->list_lock, flags);
+               }
+               inuse = new.inuse;
  
-       if (unlikely(PageSlubFrozen(page))) {
-               stat(s, FREE_FROZEN);
-               goto out_unlock;
-       }
+       } while (!cmpxchg_double_slab(s, page,
+               prior, counters,
+               object, new.counters,
+               "__slab_free"));
  
-       if (unlikely(!page->inuse))
-               goto slab_empty;
+       if (likely(!n)) {
+                 /*
+                * The list lock was not taken therefore no list
+                * activity can be necessary.
+                */
+                 if (was_frozen)
+                         stat(s, FREE_FROZEN);
+                 return;
+         }
  
        /*
-        * Objects left in the slab. If it was not on the partial list before
-        * then add it.
+        * was_frozen may have been set after we acquired the list_lock in
+        * an earlier loop. So we need to check it here again.
         */
-       if (unlikely(!prior)) {
-               add_partial(get_node(s, page_to_nid(page)), page, 1);
-               stat(s, FREE_ADD_PARTIAL);
-       }
+       if (was_frozen)
+               stat(s, FREE_FROZEN);
+       else {
+               if (unlikely(!inuse && n->nr_partial > s->min_partial))
+                         goto slab_empty;
  
- out_unlock:
-       slab_unlock(page);
-       local_irq_restore(flags);
+               /*
+                * Objects left in the slab. If it was not on the partial list before
+                * then add it.
+                */
+               if (unlikely(!prior)) {
+                       remove_full(s, page);
+                       add_partial(n, page, 0);
+                       stat(s, FREE_ADD_PARTIAL);
+               }
+       }
+       spin_unlock_irqrestore(&n->list_lock, flags);
        return;
  
  slab_empty:
                /*
                 * Slab still on the partial list.
                 */
-               remove_partial(s, page);
+               remove_partial(n, page);
                stat(s, FREE_REMOVE_PARTIAL);
        }
-       slab_unlock(page);
-       local_irq_restore(flags);
+       spin_unlock_irqrestore(&n->list_lock, flags);
        stat(s, FREE_SLAB);
        discard_slab(s, page);
  }
@@@ -2415,7 -2602,6 +2667,6 @@@ static void early_kmem_cache_node_alloc
  {
        struct page *page;
        struct kmem_cache_node *n;
-       unsigned long flags;
  
        BUG_ON(kmem_cache_node->size < sizeof(struct kmem_cache_node));
  
        BUG_ON(!n);
        page->freelist = get_freepointer(kmem_cache_node, n);
        page->inuse++;
+       page->frozen = 0;
        kmem_cache_node->node[node] = n;
  #ifdef CONFIG_SLUB_DEBUG
        init_object(kmem_cache_node, n, SLUB_RED_ACTIVE);
        init_kmem_cache_node(n, kmem_cache_node);
        inc_slabs_node(kmem_cache_node, node, page->objects);
  
-       /*
-        * lockdep requires consistent irq usage for each lock
-        * so even though there cannot be a race this early in
-        * the boot sequence, we still disable irqs.
-        */
-       local_irq_save(flags);
        add_partial(n, page, 0);
-       local_irq_restore(flags);
  }
  
  static void free_kmem_cache_nodes(struct kmem_cache *s)
@@@ -2654,6 -2834,12 +2899,12 @@@ static int kmem_cache_open(struct kmem_
                }
        }
  
+ #ifdef CONFIG_CMPXCHG_DOUBLE
+       if (system_has_cmpxchg_double() && (s->flags & SLAB_DEBUG_FLAGS) == 0)
+               /* Enable fast mode */
+               s->flags |= __CMPXCHG_DOUBLE;
+ #endif
        /*
         * The larger the object size is, the more pages we want on the partial
         * list to avoid pounding the page allocator excessively.
@@@ -2726,7 -2912,7 +2977,7 @@@ static void free_partial(struct kmem_ca
        spin_lock_irqsave(&n->list_lock, flags);
        list_for_each_entry_safe(page, h, &n->partial, lru) {
                if (!page->inuse) {
-                       __remove_partial(n, page);
+                       remove_partial(n, page);
                        discard_slab(s, page);
                } else {
                        list_slab_objects(s, page,
@@@ -2993,42 -3179,6 +3244,42 @@@ size_t ksize(const void *object
  }
  EXPORT_SYMBOL(ksize);
  
 +#ifdef CONFIG_SLUB_DEBUG
 +bool verify_mem_not_deleted(const void *x)
 +{
 +      struct page *page;
 +      void *object = (void *)x;
 +      unsigned long flags;
 +      bool rv;
 +
 +      if (unlikely(ZERO_OR_NULL_PTR(x)))
 +              return false;
 +
 +      local_irq_save(flags);
 +
 +      page = virt_to_head_page(x);
 +      if (unlikely(!PageSlab(page))) {
 +              /* maybe it was from stack? */
 +              rv = true;
 +              goto out_unlock;
 +      }
 +
 +      slab_lock(page);
 +      if (on_freelist(page->slab, page, object)) {
 +              object_err(page->slab, page, object, "Object is on free-list");
 +              rv = false;
 +      } else {
 +              rv = true;
 +      }
 +      slab_unlock(page);
 +
 +out_unlock:
 +      local_irq_restore(flags);
 +      return rv;
 +}
 +EXPORT_SYMBOL(verify_mem_not_deleted);
 +#endif
 +
  void kfree(const void *x)
  {
        struct page *page;
@@@ -3094,14 -3244,8 +3345,8 @@@ int kmem_cache_shrink(struct kmem_cach
                 * list_lock. page->inuse here is the upper limit.
                 */
                list_for_each_entry_safe(page, t, &n->partial, lru) {
-                       if (!page->inuse && slab_trylock(page)) {
-                               /*
-                                * Must hold slab lock here because slab_free
-                                * may have freed the last object and be
-                                * waiting to release the slab.
-                                */
-                               __remove_partial(n, page);
-                               slab_unlock(page);
+                       if (!page->inuse) {
+                               remove_partial(n, page);
                                discard_slab(s, page);
                        } else {
                                list_move(&page->lru,
@@@ -3689,12 -3833,9 +3934,9 @@@ static int validate_slab(struct kmem_ca
  static void validate_slab_slab(struct kmem_cache *s, struct page *page,
                                                unsigned long *map)
  {
-       if (slab_trylock(page)) {
-               validate_slab(s, page, map);
-               slab_unlock(page);
-       } else
-               printk(KERN_INFO "SLUB %s: Skipped busy slab 0x%p\n",
-                       s->name, page);
+       slab_lock(page);
+       validate_slab(s, page, map);
+       slab_unlock(page);
  }
  
  static int validate_slab_node(struct kmem_cache *s,
@@@ -4159,7 -4300,7 +4401,7 @@@ static int any_slab_objects(struct kmem
  #endif
  
  #define to_slab_attr(n) container_of(n, struct slab_attribute, attr)
 -#define to_slab(n) container_of(n, struct kmem_cache, kobj);
 +#define to_slab(n) container_of(n, struct kmem_cache, kobj)
  
  struct slab_attribute {
        struct attribute attr;
@@@ -4342,8 -4483,10 +4584,10 @@@ static ssize_t sanity_checks_store(stru
                                const char *buf, size_t length)
  {
        s->flags &= ~SLAB_DEBUG_FREE;
-       if (buf[0] == '1')
+       if (buf[0] == '1') {
+               s->flags &= ~__CMPXCHG_DOUBLE;
                s->flags |= SLAB_DEBUG_FREE;
+       }
        return length;
  }
  SLAB_ATTR(sanity_checks);
@@@ -4357,8 -4500,10 +4601,10 @@@ static ssize_t trace_store(struct kmem_
                                                        size_t length)
  {
        s->flags &= ~SLAB_TRACE;
-       if (buf[0] == '1')
+       if (buf[0] == '1') {
+               s->flags &= ~__CMPXCHG_DOUBLE;
                s->flags |= SLAB_TRACE;
+       }
        return length;
  }
  SLAB_ATTR(trace);
@@@ -4375,8 -4520,10 +4621,10 @@@ static ssize_t red_zone_store(struct km
                return -EBUSY;
  
        s->flags &= ~SLAB_RED_ZONE;
-       if (buf[0] == '1')
+       if (buf[0] == '1') {
+               s->flags &= ~__CMPXCHG_DOUBLE;
                s->flags |= SLAB_RED_ZONE;
+       }
        calculate_sizes(s, -1);
        return length;
  }
@@@ -4394,8 -4541,10 +4642,10 @@@ static ssize_t poison_store(struct kmem
                return -EBUSY;
  
        s->flags &= ~SLAB_POISON;
-       if (buf[0] == '1')
+       if (buf[0] == '1') {
+               s->flags &= ~__CMPXCHG_DOUBLE;
                s->flags |= SLAB_POISON;
+       }
        calculate_sizes(s, -1);
        return length;
  }
@@@ -4413,8 -4562,10 +4663,10 @@@ static ssize_t store_user_store(struct 
                return -EBUSY;
  
        s->flags &= ~SLAB_STORE_USER;
-       if (buf[0] == '1')
+       if (buf[0] == '1') {
+               s->flags &= ~__CMPXCHG_DOUBLE;
                s->flags |= SLAB_STORE_USER;
+       }
        calculate_sizes(s, -1);
        return length;
  }
@@@ -4579,6 -4730,7 +4831,7 @@@ STAT_ATTR(FREE_REMOVE_PARTIAL, free_rem
  STAT_ATTR(ALLOC_FROM_PARTIAL, alloc_from_partial);
  STAT_ATTR(ALLOC_SLAB, alloc_slab);
  STAT_ATTR(ALLOC_REFILL, alloc_refill);
+ STAT_ATTR(ALLOC_NODE_MISMATCH, alloc_node_mismatch);
  STAT_ATTR(FREE_SLAB, free_slab);
  STAT_ATTR(CPUSLAB_FLUSH, cpuslab_flush);
  STAT_ATTR(DEACTIVATE_FULL, deactivate_full);
@@@ -4586,7 -4738,10 +4839,10 @@@ STAT_ATTR(DEACTIVATE_EMPTY, deactivate_
  STAT_ATTR(DEACTIVATE_TO_HEAD, deactivate_to_head);
  STAT_ATTR(DEACTIVATE_TO_TAIL, deactivate_to_tail);
  STAT_ATTR(DEACTIVATE_REMOTE_FREES, deactivate_remote_frees);
+ STAT_ATTR(DEACTIVATE_BYPASS, deactivate_bypass);
  STAT_ATTR(ORDER_FALLBACK, order_fallback);
+ STAT_ATTR(CMPXCHG_DOUBLE_CPU_FAIL, cmpxchg_double_cpu_fail);
+ STAT_ATTR(CMPXCHG_DOUBLE_FAIL, cmpxchg_double_fail);
  #endif
  
  static struct attribute *slab_attrs[] = {
        &alloc_from_partial_attr.attr,
        &alloc_slab_attr.attr,
        &alloc_refill_attr.attr,
+       &alloc_node_mismatch_attr.attr,
        &free_slab_attr.attr,
        &cpuslab_flush_attr.attr,
        &deactivate_full_attr.attr,
        &deactivate_to_head_attr.attr,
        &deactivate_to_tail_attr.attr,
        &deactivate_remote_frees_attr.attr,
+       &deactivate_bypass_attr.attr,
        &order_fallback_attr.attr,
+       &cmpxchg_double_fail_attr.attr,
+       &cmpxchg_double_cpu_fail_attr.attr,
  #endif
  #ifdef CONFIG_FAILSLAB
        &failslab_attr.attr,