idle: Remove GENERIC_IDLE_LOOP config switch
[linux-3.10.git] / lib / debugobjects.c
index 90e46fa..37061ed 100644 (file)
@@ -9,8 +9,10 @@
  */
 #include <linux/debugobjects.h>
 #include <linux/interrupt.h>
+#include <linux/sched.h>
 #include <linux/seq_file.h>
 #include <linux/debugfs.h>
+#include <linux/slab.h>
 #include <linux/hash.h>
 
 #define ODEBUG_HASH_BITS       14
 
 struct debug_bucket {
        struct hlist_head       list;
-       spinlock_t              lock;
+       raw_spinlock_t          lock;
 };
 
 static struct debug_bucket     obj_hash[ODEBUG_HASH_SIZE];
 
-static struct debug_obj                obj_static_pool[ODEBUG_POOL_SIZE];
+static struct debug_obj                obj_static_pool[ODEBUG_POOL_SIZE] __initdata;
 
-static DEFINE_SPINLOCK(pool_lock);
+static DEFINE_RAW_SPINLOCK(pool_lock);
 
 static HLIST_HEAD(obj_pool);
 
@@ -50,6 +52,9 @@ static int                    debug_objects_enabled __read_mostly
 
 static struct debug_obj_descr  *descr_test  __read_mostly;
 
+static void free_obj_work(struct work_struct *work);
+static DECLARE_WORK(debug_obj_work, free_obj_work);
+
 static int __init enable_object_debug(char *str)
 {
        debug_objects_enabled = 1;
@@ -74,30 +79,29 @@ static const char *obj_states[ODEBUG_STATE_MAX] = {
        [ODEBUG_STATE_NOTAVAILABLE]     = "not available",
 };
 
-static int fill_pool(void)
+static void fill_pool(void)
 {
        gfp_t gfp = GFP_ATOMIC | __GFP_NORETRY | __GFP_NOWARN;
        struct debug_obj *new;
        unsigned long flags;
 
        if (likely(obj_pool_free >= ODEBUG_POOL_MIN_LEVEL))
-               return obj_pool_free;
+               return;
 
        if (unlikely(!obj_cache))
-               return obj_pool_free;
+               return;
 
        while (obj_pool_free < ODEBUG_POOL_MIN_LEVEL) {
 
                new = kmem_cache_zalloc(obj_cache, gfp);
                if (!new)
-                       return obj_pool_free;
+                       return;
 
-               spin_lock_irqsave(&pool_lock, flags);
+               raw_spin_lock_irqsave(&pool_lock, flags);
                hlist_add_head(&new->node, &obj_pool);
                obj_pool_free++;
-               spin_unlock_irqrestore(&pool_lock, flags);
+               raw_spin_unlock_irqrestore(&pool_lock, flags);
        }
-       return obj_pool_free;
 }
 
 /*
@@ -105,11 +109,10 @@ static int fill_pool(void)
  */
 static struct debug_obj *lookup_object(void *addr, struct debug_bucket *b)
 {
-       struct hlist_node *node;
        struct debug_obj *obj;
        int cnt = 0;
 
-       hlist_for_each_entry(obj, node, &b->list, node) {
+       hlist_for_each_entry(obj, &b->list, node) {
                cnt++;
                if (obj->object == addr)
                        return obj;
@@ -129,13 +132,14 @@ alloc_object(void *addr, struct debug_bucket *b, struct debug_obj_descr *descr)
 {
        struct debug_obj *obj = NULL;
 
-       spin_lock(&pool_lock);
+       raw_spin_lock(&pool_lock);
        if (obj_pool.first) {
                obj         = hlist_entry(obj_pool.first, typeof(*obj), node);
 
                obj->object = addr;
                obj->descr  = descr;
                obj->state  = ODEBUG_STATE_NONE;
+               obj->astate = 0;
                hlist_del(&obj->node);
 
                hlist_add_head(&obj->node, &b->list);
@@ -148,31 +152,57 @@ alloc_object(void *addr, struct debug_bucket *b, struct debug_obj_descr *descr)
                if (obj_pool_free < obj_pool_min_free)
                        obj_pool_min_free = obj_pool_free;
        }
-       spin_unlock(&pool_lock);
+       raw_spin_unlock(&pool_lock);
 
        return obj;
 }
 
 /*
- * Put the object back into the pool or give it back to kmem_cache:
+ * workqueue function to free objects.
  */
-static void free_object(struct debug_obj *obj)
+static void free_obj_work(struct work_struct *work)
 {
-       unsigned long idx = (unsigned long)(obj - obj_static_pool);
+       struct debug_obj *obj;
        unsigned long flags;
 
-       if (obj_pool_free < ODEBUG_POOL_SIZE || idx < ODEBUG_POOL_SIZE) {
-               spin_lock_irqsave(&pool_lock, flags);
-               hlist_add_head(&obj->node, &obj_pool);
-               obj_pool_free++;
-               obj_pool_used--;
-               spin_unlock_irqrestore(&pool_lock, flags);
-       } else {
-               spin_lock_irqsave(&pool_lock, flags);
-               obj_pool_used--;
-               spin_unlock_irqrestore(&pool_lock, flags);
+       raw_spin_lock_irqsave(&pool_lock, flags);
+       while (obj_pool_free > ODEBUG_POOL_SIZE) {
+               obj = hlist_entry(obj_pool.first, typeof(*obj), node);
+               hlist_del(&obj->node);
+               obj_pool_free--;
+               /*
+                * We release pool_lock across kmem_cache_free() to
+                * avoid contention on pool_lock.
+                */
+               raw_spin_unlock_irqrestore(&pool_lock, flags);
                kmem_cache_free(obj_cache, obj);
+               raw_spin_lock_irqsave(&pool_lock, flags);
        }
+       raw_spin_unlock_irqrestore(&pool_lock, flags);
+}
+
+/*
+ * Put the object back into the pool and schedule work to free objects
+ * if necessary.
+ */
+static void free_object(struct debug_obj *obj)
+{
+       unsigned long flags;
+       int sched = 0;
+
+       raw_spin_lock_irqsave(&pool_lock, flags);
+       /*
+        * schedule work when the pool is filled and the cache is
+        * initialized:
+        */
+       if (obj_pool_free > ODEBUG_POOL_SIZE && obj_cache)
+               sched = keventd_up() && !work_pending(&debug_obj_work);
+       hlist_add_head(&obj->node, &obj_pool);
+       obj_pool_free++;
+       obj_pool_used--;
+       raw_spin_unlock_irqrestore(&pool_lock, flags);
+       if (sched)
+               schedule_work(&debug_obj_work);
 }
 
 /*
@@ -182,7 +212,7 @@ static void free_object(struct debug_obj *obj)
 static void debug_objects_oom(void)
 {
        struct debug_bucket *db = obj_hash;
-       struct hlist_node *node, *tmp;
+       struct hlist_node *tmp;
        HLIST_HEAD(freelist);
        struct debug_obj *obj;
        unsigned long flags;
@@ -191,12 +221,12 @@ static void debug_objects_oom(void)
        printk(KERN_WARNING "ODEBUG: Out of memory. ODEBUG disabled\n");
 
        for (i = 0; i < ODEBUG_HASH_SIZE; i++, db++) {
-               spin_lock_irqsave(&db->lock, flags);
+               raw_spin_lock_irqsave(&db->lock, flags);
                hlist_move_list(&db->list, &freelist);
-               spin_unlock_irqrestore(&db->lock, flags);
+               raw_spin_unlock_irqrestore(&db->lock, flags);
 
                /* Now free them */
-               hlist_for_each_entry_safe(obj, node, tmp, &freelist, node) {
+               hlist_for_each_entry_safe(obj, tmp, &freelist, node) {
                        hlist_del(&obj->node);
                        free_object(obj);
                }
@@ -217,12 +247,17 @@ static struct debug_bucket *get_bucket(unsigned long addr)
 
 static void debug_print_object(struct debug_obj *obj, char *msg)
 {
+       struct debug_obj_descr *descr = obj->descr;
        static int limit;
 
-       if (limit < 5 && obj->descr != descr_test) {
+       if (limit < 5 && descr != descr_test) {
+               void *hint = descr->debug_hint ?
+                       descr->debug_hint(obj->object) : NULL;
                limit++;
-               WARN(1, KERN_ERR "ODEBUG: %s %s object type: %s\n", msg,
-                      obj_states[obj->state], obj->descr->name);
+               WARN(1, KERN_ERR "ODEBUG: %s %s (active state %u) "
+                                "object type: %s hint: %pS\n",
+                       msg, obj_states[obj->state], obj->astate,
+                       descr->name, hint);
        }
        debug_objects_warnings++;
 }
@@ -231,12 +266,16 @@ static void debug_print_object(struct debug_obj *obj, char *msg)
  * Try to repair the damage, so we have a better chance to get useful
  * debug output.
  */
-static void
+static int
 debug_object_fixup(int (*fixup)(void *addr, enum debug_obj_state state),
                   void * addr, enum debug_obj_state state)
 {
+       int fixed = 0;
+
        if (fixup)
-               debug_objects_fixups += fixup(addr, state);
+               fixed = fixup(addr, state);
+       debug_objects_fixups += fixed;
+       return fixed;
 }
 
 static void debug_object_is_on_stack(void *addr, int onstack)
@@ -273,14 +312,14 @@ __debug_object_init(void *addr, struct debug_obj_descr *descr, int onstack)
 
        db = get_bucket((unsigned long) addr);
 
-       spin_lock_irqsave(&db->lock, flags);
+       raw_spin_lock_irqsave(&db->lock, flags);
 
        obj = lookup_object(addr, db);
        if (!obj) {
                obj = alloc_object(addr, db, descr);
                if (!obj) {
                        debug_objects_enabled = 0;
-                       spin_unlock_irqrestore(&db->lock, flags);
+                       raw_spin_unlock_irqrestore(&db->lock, flags);
                        debug_objects_oom();
                        return;
                }
@@ -297,7 +336,7 @@ __debug_object_init(void *addr, struct debug_obj_descr *descr, int onstack)
        case ODEBUG_STATE_ACTIVE:
                debug_print_object(obj, "init");
                state = obj->state;
-               spin_unlock_irqrestore(&db->lock, flags);
+               raw_spin_unlock_irqrestore(&db->lock, flags);
                debug_object_fixup(descr->fixup_init, addr, state);
                return;
 
@@ -308,7 +347,7 @@ __debug_object_init(void *addr, struct debug_obj_descr *descr, int onstack)
                break;
        }
 
-       spin_unlock_irqrestore(&db->lock, flags);
+       raw_spin_unlock_irqrestore(&db->lock, flags);
 }
 
 /**
@@ -349,13 +388,16 @@ void debug_object_activate(void *addr, struct debug_obj_descr *descr)
        struct debug_bucket *db;
        struct debug_obj *obj;
        unsigned long flags;
+       struct debug_obj o = { .object = addr,
+                              .state = ODEBUG_STATE_NOTAVAILABLE,
+                              .descr = descr };
 
        if (!debug_objects_enabled)
                return;
 
        db = get_bucket((unsigned long) addr);
 
-       spin_lock_irqsave(&db->lock, flags);
+       raw_spin_lock_irqsave(&db->lock, flags);
 
        obj = lookup_object(addr, db);
        if (obj) {
@@ -368,7 +410,7 @@ void debug_object_activate(void *addr, struct debug_obj_descr *descr)
                case ODEBUG_STATE_ACTIVE:
                        debug_print_object(obj, "activate");
                        state = obj->state;
-                       spin_unlock_irqrestore(&db->lock, flags);
+                       raw_spin_unlock_irqrestore(&db->lock, flags);
                        debug_object_fixup(descr->fixup_activate, addr, state);
                        return;
 
@@ -378,18 +420,19 @@ void debug_object_activate(void *addr, struct debug_obj_descr *descr)
                default:
                        break;
                }
-               spin_unlock_irqrestore(&db->lock, flags);
+               raw_spin_unlock_irqrestore(&db->lock, flags);
                return;
        }
 
-       spin_unlock_irqrestore(&db->lock, flags);
+       raw_spin_unlock_irqrestore(&db->lock, flags);
        /*
         * This happens when a static object is activated. We
         * let the type specific code decide whether this is
         * true or not.
         */
-       debug_object_fixup(descr->fixup_activate, addr,
-                          ODEBUG_STATE_NOTAVAILABLE);
+       if (debug_object_fixup(descr->fixup_activate, addr,
+                          ODEBUG_STATE_NOTAVAILABLE))
+               debug_print_object(&o, "activate");
 }
 
 /**
@@ -408,7 +451,7 @@ void debug_object_deactivate(void *addr, struct debug_obj_descr *descr)
 
        db = get_bucket((unsigned long) addr);
 
-       spin_lock_irqsave(&db->lock, flags);
+       raw_spin_lock_irqsave(&db->lock, flags);
 
        obj = lookup_object(addr, db);
        if (obj) {
@@ -416,7 +459,10 @@ void debug_object_deactivate(void *addr, struct debug_obj_descr *descr)
                case ODEBUG_STATE_INIT:
                case ODEBUG_STATE_INACTIVE:
                case ODEBUG_STATE_ACTIVE:
-                       obj->state = ODEBUG_STATE_INACTIVE;
+                       if (!obj->astate)
+                               obj->state = ODEBUG_STATE_INACTIVE;
+                       else
+                               debug_print_object(obj, "deactivate");
                        break;
 
                case ODEBUG_STATE_DESTROYED:
@@ -433,7 +479,7 @@ void debug_object_deactivate(void *addr, struct debug_obj_descr *descr)
                debug_print_object(&o, "deactivate");
        }
 
-       spin_unlock_irqrestore(&db->lock, flags);
+       raw_spin_unlock_irqrestore(&db->lock, flags);
 }
 
 /**
@@ -453,7 +499,7 @@ void debug_object_destroy(void *addr, struct debug_obj_descr *descr)
 
        db = get_bucket((unsigned long) addr);
 
-       spin_lock_irqsave(&db->lock, flags);
+       raw_spin_lock_irqsave(&db->lock, flags);
 
        obj = lookup_object(addr, db);
        if (!obj)
@@ -468,7 +514,7 @@ void debug_object_destroy(void *addr, struct debug_obj_descr *descr)
        case ODEBUG_STATE_ACTIVE:
                debug_print_object(obj, "destroy");
                state = obj->state;
-               spin_unlock_irqrestore(&db->lock, flags);
+               raw_spin_unlock_irqrestore(&db->lock, flags);
                debug_object_fixup(descr->fixup_destroy, addr, state);
                return;
 
@@ -479,7 +525,7 @@ void debug_object_destroy(void *addr, struct debug_obj_descr *descr)
                break;
        }
 out_unlock:
-       spin_unlock_irqrestore(&db->lock, flags);
+       raw_spin_unlock_irqrestore(&db->lock, flags);
 }
 
 /**
@@ -499,7 +545,7 @@ void debug_object_free(void *addr, struct debug_obj_descr *descr)
 
        db = get_bucket((unsigned long) addr);
 
-       spin_lock_irqsave(&db->lock, flags);
+       raw_spin_lock_irqsave(&db->lock, flags);
 
        obj = lookup_object(addr, db);
        if (!obj)
@@ -509,24 +555,109 @@ void debug_object_free(void *addr, struct debug_obj_descr *descr)
        case ODEBUG_STATE_ACTIVE:
                debug_print_object(obj, "free");
                state = obj->state;
-               spin_unlock_irqrestore(&db->lock, flags);
+               raw_spin_unlock_irqrestore(&db->lock, flags);
                debug_object_fixup(descr->fixup_free, addr, state);
                return;
        default:
                hlist_del(&obj->node);
-               spin_unlock_irqrestore(&db->lock, flags);
+               raw_spin_unlock_irqrestore(&db->lock, flags);
                free_object(obj);
                return;
        }
 out_unlock:
-       spin_unlock_irqrestore(&db->lock, flags);
+       raw_spin_unlock_irqrestore(&db->lock, flags);
+}
+
+/**
+ * debug_object_assert_init - debug checks when object should be init-ed
+ * @addr:      address of the object
+ * @descr:     pointer to an object specific debug description structure
+ */
+void debug_object_assert_init(void *addr, struct debug_obj_descr *descr)
+{
+       struct debug_bucket *db;
+       struct debug_obj *obj;
+       unsigned long flags;
+
+       if (!debug_objects_enabled)
+               return;
+
+       db = get_bucket((unsigned long) addr);
+
+       raw_spin_lock_irqsave(&db->lock, flags);
+
+       obj = lookup_object(addr, db);
+       if (!obj) {
+               struct debug_obj o = { .object = addr,
+                                      .state = ODEBUG_STATE_NOTAVAILABLE,
+                                      .descr = descr };
+
+               raw_spin_unlock_irqrestore(&db->lock, flags);
+               /*
+                * Maybe the object is static.  Let the type specific
+                * code decide what to do.
+                */
+               if (debug_object_fixup(descr->fixup_assert_init, addr,
+                                      ODEBUG_STATE_NOTAVAILABLE))
+                       debug_print_object(&o, "assert_init");
+               return;
+       }
+
+       raw_spin_unlock_irqrestore(&db->lock, flags);
+}
+
+/**
+ * debug_object_active_state - debug checks object usage state machine
+ * @addr:      address of the object
+ * @descr:     pointer to an object specific debug description structure
+ * @expect:    expected state
+ * @next:      state to move to if expected state is found
+ */
+void
+debug_object_active_state(void *addr, struct debug_obj_descr *descr,
+                         unsigned int expect, unsigned int next)
+{
+       struct debug_bucket *db;
+       struct debug_obj *obj;
+       unsigned long flags;
+
+       if (!debug_objects_enabled)
+               return;
+
+       db = get_bucket((unsigned long) addr);
+
+       raw_spin_lock_irqsave(&db->lock, flags);
+
+       obj = lookup_object(addr, db);
+       if (obj) {
+               switch (obj->state) {
+               case ODEBUG_STATE_ACTIVE:
+                       if (obj->astate == expect)
+                               obj->astate = next;
+                       else
+                               debug_print_object(obj, "active_state");
+                       break;
+
+               default:
+                       debug_print_object(obj, "active_state");
+                       break;
+               }
+       } else {
+               struct debug_obj o = { .object = addr,
+                                      .state = ODEBUG_STATE_NOTAVAILABLE,
+                                      .descr = descr };
+
+               debug_print_object(&o, "active_state");
+       }
+
+       raw_spin_unlock_irqrestore(&db->lock, flags);
 }
 
 #ifdef CONFIG_DEBUG_OBJECTS_FREE
 static void __debug_check_no_obj_freed(const void *address, unsigned long size)
 {
        unsigned long flags, oaddr, saddr, eaddr, paddr, chunks;
-       struct hlist_node *node, *tmp;
+       struct hlist_node *tmp;
        HLIST_HEAD(freelist);
        struct debug_obj_descr *descr;
        enum debug_obj_state state;
@@ -545,8 +676,8 @@ static void __debug_check_no_obj_freed(const void *address, unsigned long size)
 
 repeat:
                cnt = 0;
-               spin_lock_irqsave(&db->lock, flags);
-               hlist_for_each_entry_safe(obj, node, tmp, &db->list, node) {
+               raw_spin_lock_irqsave(&db->lock, flags);
+               hlist_for_each_entry_safe(obj, tmp, &db->list, node) {
                        cnt++;
                        oaddr = (unsigned long) obj->object;
                        if (oaddr < saddr || oaddr >= eaddr)
@@ -557,7 +688,7 @@ repeat:
                                debug_print_object(obj, "free");
                                descr = obj->descr;
                                state = obj->state;
-                               spin_unlock_irqrestore(&db->lock, flags);
+                               raw_spin_unlock_irqrestore(&db->lock, flags);
                                debug_object_fixup(descr->fixup_free,
                                                   (void *) oaddr, state);
                                goto repeat;
@@ -567,10 +698,10 @@ repeat:
                                break;
                        }
                }
-               spin_unlock_irqrestore(&db->lock, flags);
+               raw_spin_unlock_irqrestore(&db->lock, flags);
 
                /* Now free them */
-               hlist_for_each_entry_safe(obj, node, tmp, &freelist, node) {
+               hlist_for_each_entry_safe(obj, tmp, &freelist, node) {
                        hlist_del(&obj->node);
                        free_object(obj);
                }
@@ -685,17 +816,9 @@ static int __init fixup_activate(void *addr, enum debug_obj_state state)
                if (obj->static_init == 1) {
                        debug_object_init(obj, &descr_type_test);
                        debug_object_activate(obj, &descr_type_test);
-                       /*
-                        * Real code should return 0 here ! This is
-                        * not a fixup of some bad behaviour. We
-                        * merily call the debug_init function to keep
-                        * track of the object.
-                        */
-                       return 1;
-               } else {
-                       /* Real code needs to emit a warning here */
+                       return 0;
                }
-               return 0;
+               return 1;
 
        case ODEBUG_STATE_ACTIVE:
                debug_object_deactivate(obj, &descr_type_test);
@@ -743,7 +866,7 @@ static int __init fixup_free(void *addr, enum debug_obj_state state)
        }
 }
 
-static int
+static int __init
 check_results(void *addr, enum debug_obj_state state, int fixups, int warnings)
 {
        struct debug_bucket *db;
@@ -753,7 +876,7 @@ check_results(void *addr, enum debug_obj_state state, int fixups, int warnings)
 
        db = get_bucket((unsigned long) addr);
 
-       spin_lock_irqsave(&db->lock, flags);
+       raw_spin_lock_irqsave(&db->lock, flags);
 
        obj = lookup_object(addr, db);
        if (!obj && state != ODEBUG_STATE_NONE) {
@@ -777,7 +900,7 @@ check_results(void *addr, enum debug_obj_state state, int fixups, int warnings)
        }
        res = 0;
 out:
-       spin_unlock_irqrestore(&db->lock, flags);
+       raw_spin_unlock_irqrestore(&db->lock, flags);
        if (res)
                debug_objects_enabled = 0;
        return res;
@@ -834,7 +957,7 @@ static void __init debug_objects_selftest(void)
 
        obj.static_init = 1;
        debug_object_activate(&obj, &descr_type_test);
-       if (check_results(&obj, ODEBUG_STATE_ACTIVE, ++fixups, warnings))
+       if (check_results(&obj, ODEBUG_STATE_ACTIVE, fixups, warnings))
                goto out;
        debug_object_init(&obj, &descr_type_test);
        if (check_results(&obj, ODEBUG_STATE_INIT, ++fixups, ++warnings))
@@ -877,13 +1000,70 @@ void __init debug_objects_early_init(void)
        int i;
 
        for (i = 0; i < ODEBUG_HASH_SIZE; i++)
-               spin_lock_init(&obj_hash[i].lock);
+               raw_spin_lock_init(&obj_hash[i].lock);
 
        for (i = 0; i < ODEBUG_POOL_SIZE; i++)
                hlist_add_head(&obj_static_pool[i].node, &obj_pool);
 }
 
 /*
+ * Convert the statically allocated objects to dynamic ones:
+ */
+static int __init debug_objects_replace_static_objects(void)
+{
+       struct debug_bucket *db = obj_hash;
+       struct hlist_node *tmp;
+       struct debug_obj *obj, *new;
+       HLIST_HEAD(objects);
+       int i, cnt = 0;
+
+       for (i = 0; i < ODEBUG_POOL_SIZE; i++) {
+               obj = kmem_cache_zalloc(obj_cache, GFP_KERNEL);
+               if (!obj)
+                       goto free;
+               hlist_add_head(&obj->node, &objects);
+       }
+
+       /*
+        * When debug_objects_mem_init() is called we know that only
+        * one CPU is up, so disabling interrupts is enough
+        * protection. This avoids the lockdep hell of lock ordering.
+        */
+       local_irq_disable();
+
+       /* Remove the statically allocated objects from the pool */
+       hlist_for_each_entry_safe(obj, tmp, &obj_pool, node)
+               hlist_del(&obj->node);
+       /* Move the allocated objects to the pool */
+       hlist_move_list(&objects, &obj_pool);
+
+       /* Replace the active object references */
+       for (i = 0; i < ODEBUG_HASH_SIZE; i++, db++) {
+               hlist_move_list(&db->list, &objects);
+
+               hlist_for_each_entry(obj, &objects, node) {
+                       new = hlist_entry(obj_pool.first, typeof(*obj), node);
+                       hlist_del(&new->node);
+                       /* copy object data */
+                       *new = *obj;
+                       hlist_add_head(&new->node, &db->list);
+                       cnt++;
+               }
+       }
+       local_irq_enable();
+
+       printk(KERN_DEBUG "ODEBUG: %d of %d active objects replaced\n", cnt,
+              obj_pool_used);
+       return 0;
+free:
+       hlist_for_each_entry_safe(obj, tmp, &objects, node) {
+               hlist_del(&obj->node);
+               kmem_cache_free(obj_cache, obj);
+       }
+       return -ENOMEM;
+}
+
+/*
  * Called after the kmem_caches are functional to setup a dedicated
  * cache pool, which has the SLAB_DEBUG_OBJECTS flag set. This flag
  * prevents that the debug code is called on kmem_cache_free() for the
@@ -898,8 +1078,11 @@ void __init debug_objects_mem_init(void)
                                      sizeof (struct debug_obj), 0,
                                      SLAB_DEBUG_OBJECTS, NULL);
 
-       if (!obj_cache)
+       if (!obj_cache || debug_objects_replace_static_objects()) {
                debug_objects_enabled = 0;
-       else
+               if (obj_cache)
+                       kmem_cache_destroy(obj_cache);
+               printk(KERN_WARNING "ODEBUG: out of memory.\n");
+       } else
                debug_objects_selftest();
 }