kmemleak: Select DEBUG_FS unconditionally in DEBUG_KMEMLEAK
[linux-2.6.git] / lib / debugobjects.c
index 2755a3b..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] __initdata;
 
-static DEFINE_SPINLOCK(pool_lock);
+static DEFINE_RAW_SPINLOCK(pool_lock);
 
 static HLIST_HEAD(obj_pool);
 
@@ -95,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;
 }
@@ -132,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);
@@ -151,7 +154,7 @@ 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;
 }
@@ -164,7 +167,7 @@ static void free_obj_work(struct work_struct *work)
        struct debug_obj *obj;
        unsigned long flags;
 
-       spin_lock_irqsave(&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);
@@ -173,11 +176,11 @@ static void free_obj_work(struct work_struct *work)
                 * We release pool_lock across kmem_cache_free() to
                 * avoid contention on pool_lock.
                 */
-               spin_unlock_irqrestore(&pool_lock, flags);
+               raw_spin_unlock_irqrestore(&pool_lock, flags);
                kmem_cache_free(obj_cache, obj);
-               spin_lock_irqsave(&pool_lock, flags);
+               raw_spin_lock_irqsave(&pool_lock, flags);
        }
-       spin_unlock_irqrestore(&pool_lock, flags);
+       raw_spin_unlock_irqrestore(&pool_lock, flags);
 }
 
 /*
@@ -189,7 +192,7 @@ static void free_object(struct debug_obj *obj)
        unsigned long flags;
        int sched = 0;
 
-       spin_lock_irqsave(&pool_lock, flags);
+       raw_spin_lock_irqsave(&pool_lock, flags);
        /*
         * schedule work when the pool is filled and the cache is
         * initialized:
@@ -199,7 +202,7 @@ static void free_object(struct debug_obj *obj)
        hlist_add_head(&obj->node, &obj_pool);
        obj_pool_free++;
        obj_pool_used--;
-       spin_unlock_irqrestore(&pool_lock, flags);
+       raw_spin_unlock_irqrestore(&pool_lock, flags);
        if (sched)
                schedule_work(&debug_obj_work);
 }
@@ -220,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) {
@@ -246,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++;
 }
@@ -302,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;
                }
@@ -326,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;
 
@@ -337,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);
 }
 
 /**
@@ -384,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) {
@@ -397,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;
 
@@ -407,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
@@ -437,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) {
@@ -445,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:
@@ -462,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);
 }
 
 /**
@@ -482,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)
@@ -497,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;
 
@@ -508,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);
 }
 
 /**
@@ -528,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)
@@ -538,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
@@ -574,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;
@@ -586,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;
@@ -596,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) {
@@ -772,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;
@@ -782,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) {
@@ -806,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;
@@ -906,7 +964,7 @@ 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);
@@ -915,7 +973,7 @@ void __init debug_objects_early_init(void)
 /*
  * Convert the statically allocated objects to dynamic ones:
  */
-static int debug_objects_replace_static_objects(void)
+static int __init debug_objects_replace_static_objects(void)
 {
        struct debug_bucket *db = obj_hash;
        struct hlist_node *node, *tmp;