Bug 10918

Summary: 2.6.26-rc5: SLUB debug, lockdep warning...
Product: Memory Management Reporter: Rafael J. Wysocki (rjw)
Component: Slab AllocatorAssignee: Daniel J Blueman (daniel.blueman)
Status: CLOSED CODE_FIX    
Severity: normal CC: daniel.blueman, tglx, vegard.nossum
Priority: P1    
Hardware: All   
OS: Linux   
Kernel Version: 2.6.26-rc5 Subsystem:
Regression: Yes Bisected commit-id:
Bug Depends on:    
Bug Blocks: 10492    

Description Rafael J. Wysocki 2008-06-15 04:10:20 UTC
Subject    : 2.6.26-rc5: SLUB debug, lockdep warning...
Submitter  : "Daniel J Blueman" <daniel.blueman@gmail.com>
Date       : 2008-06-14 10:54
References : http://marc.info/?l=linux-kernel&m=121344091109597&w=4
Handled-By : "Vegard Nossum" <vegard.nossum@gmail.com>

This entry is being used for tracking a regression from 2.6.25.  Please don't
close it until the problem is fixed in the mainline.
Comment 1 Rafael J. Wysocki 2008-06-15 04:11:50 UTC
Probably caused by:

commit 3ac7fe5a4aab409bd5674d0b070bce97f9d20872
Author: Thomas Gleixner <tglx@linutronix.de>
Date:   Wed Apr 30 00:55:01 2008 -0700

    infrastructure to debug (dynamic) objects

    Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
    Signed-off-by: Ingo Molnar <mingo@elte.hu>
    Cc: Greg KH <greg@kroah.com>
    Cc: Randy Dunlap <randy.dunlap@oracle.com>
    Cc: Kay Sievers <kay.sievers@vrfy.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Comment 2 Daniel J Blueman 2008-06-15 04:22:10 UTC
Candidate fix that resolves the regression. Boot-tested on x86-64 and debugging.

Signed-off-by: Daniel J Blueman <daniel.blueman@gmail.com>
-> needs Vegard's SOB

diff --git a/lib/debugobjects.c b/lib/debugobjects.c
index a76a5e1..91109e8 100644
--- a/lib/debugobjects.c
+++ b/lib/debugobjects.c
@@ -66,6 +66,8 @@ static const char *obj_states[ODEBUG_STATE_MAX] = {

 static int fill_pool(void)
 {
+       unsigned long flags;
+
       gfp_t gfp = GFP_ATOMIC | __GFP_NORETRY | __GFP_NOWARN;
       struct debug_obj *new;

@@ -81,10 +83,10 @@ static int fill_pool(void)
               if (!new)
                       return obj_pool_free;

-               spin_lock(&pool_lock);
+               spin_lock_irqsave(&pool_lock, flags);
               hlist_add_head(&new->node, &obj_pool);
               obj_pool_free++;
-               spin_unlock(&pool_lock);
+               spin_unlock_irqrestore(&pool_lock, flags);
       }
       return obj_pool_free;
 }
@@ -117,10 +119,9 @@ static struct debug_obj *
 alloc_object(void *addr, struct debug_bucket *b, struct debug_obj_descr *descr)
 {
       struct debug_obj *obj = NULL;
-       int retry = 0;
+       unsigned long flags;

-repeat:
-       spin_lock(&pool_lock);
+       spin_lock_irqsave(&pool_lock, flags);
       if (obj_pool.first) {
               obj         = hlist_entry(obj_pool.first, typeof(*obj), node);

@@ -139,10 +140,7 @@ repeat:
               if (obj_pool_free < obj_pool_min_free)
                       obj_pool_min_free = obj_pool_free;
       }
-       spin_unlock(&pool_lock);
-
-       if (fill_pool() && !obj && !retry++)
-               goto repeat;
+       spin_unlock_irqrestore(&pool_lock, flags);

       return obj;
 }
@@ -153,17 +151,18 @@ repeat:
 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);
       }
 }
@@ -261,6 +260,8 @@ __debug_object_init(void *addr, struct debug_obj_descr *descr, int onstack)
       struct debug_obj *obj;
       unsigned long flags;

+       fill_pool();
+
       db = get_bucket((unsigned long) addr);

       spin_lock_irqsave(&db->lock, flags);
Comment 3 Rafael J. Wysocki 2008-06-15 10:40:13 UTC
Regressions list annotation:
Handled-By : "Daniel J Blueman" <daniel.blueman@gmail.com>
Patch : http://bugzilla.kernel.org/show_bug.cgi?id=10918#c2