Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/penberg...
[safe/jmp/linux-2.6] / lib / debugobjects.c
index 85b18d7..5d99be1 100644 (file)
@@ -45,7 +45,9 @@ static struct kmem_cache      *obj_cache;
 static int                     debug_objects_maxchain __read_mostly;
 static int                     debug_objects_fixups __read_mostly;
 static int                     debug_objects_warnings __read_mostly;
-static int                     debug_objects_enabled __read_mostly;
+static int                     debug_objects_enabled __read_mostly
+                               = CONFIG_DEBUG_OBJECTS_ENABLE_DEFAULT;
+
 static struct debug_obj_descr  *descr_test  __read_mostly;
 
 static int __init enable_object_debug(char *str)
@@ -112,6 +114,7 @@ static struct debug_obj *lookup_object(void *addr, struct debug_bucket *b)
 
 /*
  * Allocate a new object. If the pool is empty, switch off the debugger.
+ * Must be called with interrupts disabled.
  */
 static struct debug_obj *
 alloc_object(void *addr, struct debug_bucket *b, struct debug_obj_descr *descr)
@@ -148,17 +151,18 @@ alloc_object(void *addr, struct debug_bucket *b, struct debug_obj_descr *descr)
 static void free_object(struct debug_obj *obj)
 {
        unsigned long idx = (unsigned long)(obj - obj_static_pool);
+       unsigned long flags;
 
        if (obj_pool_free < ODEBUG_POOL_SIZE || idx < ODEBUG_POOL_SIZE) {
-               spin_lock(&pool_lock);
+               spin_lock_irqsave(&pool_lock, flags);
                hlist_add_head(&obj->node, &obj_pool);
                obj_pool_free++;
                obj_pool_used--;
-               spin_unlock(&pool_lock);
+               spin_unlock_irqrestore(&pool_lock, flags);
        } else {
-               spin_lock(&pool_lock);
+               spin_lock_irqsave(&pool_lock, flags);
                obj_pool_used--;
-               spin_unlock(&pool_lock);
+               spin_unlock_irqrestore(&pool_lock, flags);
                kmem_cache_free(obj_cache, obj);
        }
 }
@@ -171,6 +175,7 @@ static void debug_objects_oom(void)
 {
        struct debug_bucket *db = obj_hash;
        struct hlist_node *node, *tmp;
+       HLIST_HEAD(freelist);
        struct debug_obj *obj;
        unsigned long flags;
        int i;
@@ -179,11 +184,14 @@ static void debug_objects_oom(void)
 
        for (i = 0; i < ODEBUG_HASH_SIZE; i++, db++) {
                spin_lock_irqsave(&db->lock, flags);
-               hlist_for_each_entry_safe(obj, node, tmp, &db->list, node) {
+               hlist_move_list(&db->list, &freelist);
+               spin_unlock_irqrestore(&db->lock, flags);
+
+               /* Now free them */
+               hlist_for_each_entry_safe(obj, node, tmp, &freelist, node) {
                        hlist_del(&obj->node);
                        free_object(obj);
                }
-               spin_unlock_irqrestore(&db->lock, flags);
        }
 }
 
@@ -205,9 +213,8 @@ static void debug_print_object(struct debug_obj *obj, char *msg)
 
        if (limit < 5 && obj->descr != descr_test) {
                limit++;
-               printk(KERN_ERR "ODEBUG: %s %s object type: %s\n", msg,
+               WARN(1, KERN_ERR "ODEBUG: %s %s object type: %s\n", msg,
                       obj_states[obj->state], obj->descr->name);
-               WARN_ON(1);
        }
        debug_objects_warnings++;
 }
@@ -226,15 +233,13 @@ debug_object_fixup(int (*fixup)(void *addr, enum debug_obj_state state),
 
 static void debug_object_is_on_stack(void *addr, int onstack)
 {
-       void *stack = current->stack;
        int is_on_stack;
        static int limit;
 
        if (limit > 4)
                return;
 
-       is_on_stack = (addr >= stack && addr < (stack + THREAD_SIZE));
-
+       is_on_stack = object_is_on_stack(addr);
        if (is_on_stack == onstack)
                return;
 
@@ -501,8 +506,9 @@ void debug_object_free(void *addr, struct debug_obj_descr *descr)
                return;
        default:
                hlist_del(&obj->node);
+               spin_unlock_irqrestore(&db->lock, flags);
                free_object(obj);
-               break;
+               return;
        }
 out_unlock:
        spin_unlock_irqrestore(&db->lock, flags);
@@ -513,6 +519,7 @@ 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;
+       HLIST_HEAD(freelist);
        struct debug_obj_descr *descr;
        enum debug_obj_state state;
        struct debug_bucket *db;
@@ -548,11 +555,18 @@ repeat:
                                goto repeat;
                        default:
                                hlist_del(&obj->node);
-                               free_object(obj);
+                               hlist_add_head(&obj->node, &freelist);
                                break;
                        }
                }
                spin_unlock_irqrestore(&db->lock, flags);
+
+               /* Now free them */
+               hlist_for_each_entry_safe(obj, node, tmp, &freelist, node) {
+                       hlist_del(&obj->node);
+                       free_object(obj);
+               }
+
                if (cnt > debug_objects_maxchain)
                        debug_objects_maxchain = cnt;
        }
@@ -735,26 +749,22 @@ check_results(void *addr, enum debug_obj_state state, int fixups, int warnings)
 
        obj = lookup_object(addr, db);
        if (!obj && state != ODEBUG_STATE_NONE) {
-               printk(KERN_ERR "ODEBUG: selftest object not found\n");
-               WARN_ON(1);
+               WARN(1, KERN_ERR "ODEBUG: selftest object not found\n");
                goto out;
        }
        if (obj && obj->state != state) {
-               printk(KERN_ERR "ODEBUG: selftest wrong state: %d != %d\n",
+               WARN(1, KERN_ERR "ODEBUG: selftest wrong state: %d != %d\n",
                       obj->state, state);
-               WARN_ON(1);
                goto out;
        }
        if (fixups != debug_objects_fixups) {
-               printk(KERN_ERR "ODEBUG: selftest fixups failed %d != %d\n",
+               WARN(1, KERN_ERR "ODEBUG: selftest fixups failed %d != %d\n",
                       fixups, debug_objects_fixups);
-               WARN_ON(1);
                goto out;
        }
        if (warnings != debug_objects_warnings) {
-               printk(KERN_ERR "ODEBUG: selftest warnings failed %d != %d\n",
+               WARN(1, KERN_ERR "ODEBUG: selftest warnings failed %d != %d\n",
                       warnings, debug_objects_warnings);
-               WARN_ON(1);
                goto out;
        }
        res = 0;