]> Git Repo - linux.git/commitdiff
Merge branch 'slab-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/penber...
authorLinus Torvalds <[email protected]>
Fri, 22 Jul 2011 19:44:30 +0000 (12:44 -0700)
committerLinus Torvalds <[email protected]>
Fri, 22 Jul 2011 19:44:30 +0000 (12:44 -0700)
* 'slab-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/penberg/slab-2.6:
  slab: fix DEBUG_SLAB warning
  slab: shrink sizeof(struct kmem_cache)
  slab: fix DEBUG_SLAB build
  SLUB: Fix missing <linux/stacktrace.h> include
  slub: reduce overhead of slub_debug
  slub: Add method to verify memory is not freed
  slub: Enable backtrace for create/delete points
  slab allocators: Provide generic description of alignment defines
  slab, slub, slob: Unify alignment definition
  slob/lockdep: Fix gfp flags passed to lockdep

1  2 
mm/slab.c
mm/slub.c

diff --combined mm/slab.c
index d96e223de775378f78d7597d8c2d87a9e24e70a2,dc2f068c0b7d73d822f6826af35f0edf1a4f3c0d..1e523ed47c619d385465a7080f44fabe68d115cb
+++ b/mm/slab.c
@@@ -574,7 -574,9 +574,9 @@@ static struct arraycache_init initarray
      { {0, BOOT_CPUCACHE_ENTRIES, 1, 0} };
  
  /* internal cache of cache description objs */
+ static struct kmem_list3 *cache_cache_nodelists[MAX_NUMNODES];
  static struct kmem_cache cache_cache = {
+       .nodelists = cache_cache_nodelists,
        .batchcount = 1,
        .limit = BOOT_CPUCACHE_ENTRIES,
        .shared = 1,
@@@ -1492,11 -1494,10 +1494,10 @@@ void __init kmem_cache_init(void
        cache_cache.nodelists[node] = &initkmem_list3[CACHE_CACHE + node];
  
        /*
-        * struct kmem_cache size depends on nr_node_ids, which
-        * can be less than MAX_NUMNODES.
+        * struct kmem_cache size depends on nr_node_ids & nr_cpu_ids
         */
-       cache_cache.buffer_size = offsetof(struct kmem_cache, nodelists) +
-                                nr_node_ids * sizeof(struct kmem_list3 *);
+       cache_cache.buffer_size = offsetof(struct kmem_cache, array[nr_cpu_ids]) +
+                                 nr_node_ids * sizeof(struct kmem_list3 *);
  #if DEBUG
        cache_cache.obj_size = cache_cache.buffer_size;
  #endif
@@@ -2308,6 -2309,7 +2309,7 @@@ kmem_cache_create (const char *name, si
        if (!cachep)
                goto oops;
  
+       cachep->nodelists = (struct kmem_list3 **)&cachep->array[nr_cpu_ids];
  #if DEBUG
        cachep->obj_size = size;
  
@@@ -3153,12 -3155,11 +3155,11 @@@ static void *cache_alloc_debugcheck_aft
        objp += obj_offset(cachep);
        if (cachep->ctor && cachep->flags & SLAB_POISON)
                cachep->ctor(objp);
- #if ARCH_SLAB_MINALIGN
-       if ((u32)objp & (ARCH_SLAB_MINALIGN-1)) {
+       if (ARCH_SLAB_MINALIGN &&
+           ((unsigned long)objp & (ARCH_SLAB_MINALIGN-1))) {
                printk(KERN_ERR "0x%p: not aligned to ARCH_SLAB_MINALIGN=%d\n",
-                      objp, ARCH_SLAB_MINALIGN);
+                      objp, (int)ARCH_SLAB_MINALIGN);
        }
- #endif
        return objp;
  }
  #else
@@@ -3604,14 -3605,13 +3605,14 @@@ free_done
   * Release an obj back to its cache. If the obj has a constructed state, it must
   * be in this state _before_ it is released.  Called with disabled ints.
   */
 -static inline void __cache_free(struct kmem_cache *cachep, void *objp)
 +static inline void __cache_free(struct kmem_cache *cachep, void *objp,
 +    void *caller)
  {
        struct array_cache *ac = cpu_cache_get(cachep);
  
        check_irq_off();
        kmemleak_free_recursive(objp, cachep->flags);
 -      objp = cache_free_debugcheck(cachep, objp, __builtin_return_address(0));
 +      objp = cache_free_debugcheck(cachep, objp, caller);
  
        kmemcheck_slab_free(cachep, objp, obj_size(cachep));
  
@@@ -3802,7 -3802,7 +3803,7 @@@ void kmem_cache_free(struct kmem_cache 
        debug_check_no_locks_freed(objp, obj_size(cachep));
        if (!(cachep->flags & SLAB_DEBUG_OBJECTS))
                debug_check_no_obj_freed(objp, obj_size(cachep));
 -      __cache_free(cachep, objp);
 +      __cache_free(cachep, objp, __builtin_return_address(0));
        local_irq_restore(flags);
  
        trace_kmem_cache_free(_RET_IP_, objp);
@@@ -3832,7 -3832,7 +3833,7 @@@ void kfree(const void *objp
        c = virt_to_cache(objp);
        debug_check_no_locks_freed(objp, obj_size(c));
        debug_check_no_obj_freed(objp, obj_size(c));
 -      __cache_free(c, (void *)objp);
 +      __cache_free(c, (void *)objp, __builtin_return_address(0));
        local_irq_restore(flags);
  }
  EXPORT_SYMBOL(kfree);
diff --combined mm/slub.c
index 35f351f26193a47145cd8bcb7f55ae091331ca97,f899ff469f60b888b10bca3e85ae8179ba2bd4e3..ba83f3fd07572c0a6175a5c088b6739d5619fd8b
+++ b/mm/slub.c
@@@ -27,6 -27,7 +27,7 @@@
  #include <linux/memory.h>
  #include <linux/math64.h>
  #include <linux/fault-inject.h>
+ #include <linux/stacktrace.h>
  
  #include <trace/events/kmem.h>
  
@@@ -191,8 -192,12 +192,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 */
@@@ -420,6 -425,24 +425,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;
@@@ -444,6 -467,16 +467,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)
@@@ -557,10 -590,10 +590,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)
  {
@@@ -2320,12 -2385,16 +2385,12 @@@ static inline int alloc_kmem_cache_cpus
        BUILD_BUG_ON(PERCPU_DYNAMIC_EARLY_SIZE <
                        SLUB_PAGE_SHIFT * sizeof(struct kmem_cache_cpu));
  
 -#ifdef CONFIG_CMPXCHG_LOCAL
        /*
 -       * Must align to double word boundary for the double cmpxchg instructions
 -       * to work.
 +       * Must align to double word boundary for the double cmpxchg
 +       * instructions to work; see __pcpu_double_call_return_bool().
         */
 -      s->cpu_slab = __alloc_percpu(sizeof(struct kmem_cache_cpu), 2 * sizeof(void *));
 -#else
 -      /* Regular alignment is sufficient */
 -      s->cpu_slab = alloc_percpu(struct kmem_cache_cpu);
 -#endif
 +      s->cpu_slab = __alloc_percpu(sizeof(struct kmem_cache_cpu),
 +                                   2 * sizeof(void *));
  
        if (!s->cpu_slab)
                return 0;
@@@ -2928,6 -2997,42 +2993,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;
This page took 0.087483 seconds and 4 git commands to generate.