kmemleak: Select DEBUG_FS unconditionally in DEBUG_KMEMLEAK
[linux-2.6.git] / lib / debugobjects.c
index 90e46fa..9d86e45 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;
@@ -92,10 +97,10 @@ static int fill_pool(void)
                if (!new)
                        return obj_pool_free;
 
-               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;
 }
@@ -129,13 +134,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 +154,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 = !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);
 }
 
 /*
@@ -191,9 +223,9 @@ 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) {
@@ -217,12 +249,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++;
 }
@@ -273,14 +310,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 +334,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 +345,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);
 }
 
 /**
@@ -355,7 +392,7 @@ void debug_object_activate(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) {
@@ -368,7 +405,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,11 +415,11 @@ 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
@@ -408,7 +445,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 +453,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 +473,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 +493,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 +508,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 +519,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 +539,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,17 +549,64 @@ 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_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
@@ -545,7 +632,7 @@ static void __debug_check_no_obj_freed(const void *address, unsigned long size)
 
 repeat:
                cnt = 0;
-               spin_lock_irqsave(&db->lock, flags);
+               raw_spin_lock_irqsave(&db->lock, flags);
                hlist_for_each_entry_safe(obj, node, tmp, &db->list, node) {
                        cnt++;
                        oaddr = (unsigned long) obj->object;
@@ -557,7 +644,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,7 +654,7 @@ 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) {
@@ -743,7 +830,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 +840,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 +864,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;
@@ -877,13 +964,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 *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, node, 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, node, &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++;
+               }
+       }
+
+       printk(KERN_DEBUG "ODEBUG: %d of %d active objects replaced\n", cnt,
+              obj_pool_used);
+       local_irq_enable();
+       return 0;
+free:
+       hlist_for_each_entry_safe(obj, node, 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 +1042,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();
 }