the attached patch adds support for spinlock debugging with uniprocessor
kernels:
* new config option CONFIG_DEBUG_SPINLOCK_UP
* CONFIG_DEBUG_SPINLOCK only works on SMP, SMP added to config string
* support for directly including <asm/spinlock.h> removed from
<linux/spinlock.h>
Doesn't work anyway, probably the '!defined(spin_lock_init)'
was overlooked.
* DEBUG_SPINLOCKS==2 macros indented
* spin_lock saves the current owner into the spinlock structure,
file name+line printed on deadlock.
* stricter spin_trylock and spin_is_locked.
Patch against 2.4.10, tested with 2.4.10 i386
Could you apply it to the next -pre kernel?
-- Manfred <<<<<<<<<<<<<< // Kernel Version: // VERSION = 2 // PATCHLEVEL = 4 // SUBLEVEL = 10 // EXTRAVERSION = --- 2.4/arch/i386/config.in Sun Sep 23 21:20:24 2001 +++ build-2.4/arch/i386/config.in Sun Sep 30 16:10:06 2001 @@ -396,7 +396,12 @@ bool ' Debug memory allocations' CONFIG_DEBUG_SLAB bool ' Memory mapped I/O debugging' CONFIG_DEBUG_IOVIRT bool ' Magic SysRq key' CONFIG_MAGIC_SYSRQ - bool ' Spinlock debugging' CONFIG_DEBUG_SPINLOCK + if [ "$CONFIG_SMP" = "y" ]; then + bool ' Spinlock debugging (SMP)' CONFIG_DEBUG_SPINLOCK + fi + if [ "$CONFIG_SMP" = "n" ]; then + bool ' Spinlock debugging (UP)' CONFIG_DEBUG_SPINLOCK_UP + fi bool ' Verbose BUG() reporting (adds 70K)' CONFIG_DEBUG_BUGVERBOSE fi --- 2.4/include/linux/spinlock.h Sat Jul 21 22:09:10 2001 +++ build-2.4/include/linux/spinlock.h Sun Sep 30 16:58:22 2001 @@ -33,12 +33,13 @@ #ifdef CONFIG_SMP #include <asm/spinlock.h> +#else -#elif !defined(spin_lock_init) /* !SMP and spin_lock_init not previously - defined (e.g. by including asm/spinlock.h */ - -#define DEBUG_SPINLOCKS 0 /* 0 == no debugging, 1 == maintain lock state, 2 == full debug */ - +#ifdef CONFIG_DEBUG_SPINLOCK_UP +#define DEBUG_SPINLOCKS 2 /* 0 == no debugging, 1 == maintain lock state, 2 == full debug */ +#else +#define DEBUG_SPINLOCKS 0 +#endif #if (DEBUG_SPINLOCKS < 1) #define atomic_dec_and_lock(atomic,lock) atomic_dec_and_test(atomic) @@ -84,18 +85,81 @@ volatile unsigned long lock; volatile unsigned int babble; const char *module; + char *owner; + int oline; } spinlock_t; -#define SPIN_LOCK_UNLOCKED (spinlock_t) { 0, 25, __BASE_FILE__ } +#define SPIN_LOCK_UNLOCKED (spinlock_t) { 0, 10, __BASE_FILE__ , NULL, 0} #include <linux/kernel.h> -#define spin_lock_init(x) do { (x)->lock = 0; } while (0) -#define spin_is_locked(lock) (test_bit(0,(lock))) -#define spin_trylock(lock) (!test_and_set_bit(0,(lock))) - -#define spin_lock(x) do {unsigned long __spinflags; save_flags(__spinflags); cli(); if ((x)->lock&&(x)->babble) {printk("%s:%d: spin_lock(%s:%p) already locked\n", __BASE_FILE__,__LINE__, (x)->module, (x));(x)->babble--;} (x)->lock = 1; restore_flags(__spinflags);} while (0) -#define spin_unlock_wait(x) do {unsigned long __spinflags; save_flags(__spinflags); cli(); if ((x)->lock&&(x)->babble) {printk("%s:%d: spin_unlock_wait(%s:%p) deadlock\n", __BASE_FILE__,__LINE__, (x)->module, (x));(x)->babble--;} restore_flags(__spinflags);} while (0) -#define spin_unlock(x) do {unsigned long __spinflags; save_flags(__spinflags); cli(); if (!(x)->lock&&(x)->babble) {printk("%s:%d: spin_unlock(%s:%p) not locked\n", __BASE_FILE__,__LINE__, (x)->module, (x));(x)->babble--;} (x)->lock = 0; restore_flags(__spinflags);} while (0) +#define spin_lock_init(x) \ + do { \ + (x)->lock = 0; \ + (x)->babble = 5; \ + (x)->module = __BASE_FILE__; \ + (x)->owner = NULL; \ + (x)->oline = 0; \ + } while (0) +/* without debugging, spin_is_locked on UP always says + * FALSE. --> printk if already locked. */ +#define spin_is_locked(x) \ + ({ \ + if ((x)->lock&&(x)->babble) { \ + printk("%s:%d: spin_is_locked(%s:%p) already locked by %s/%d\n", \ + __BASE_FILE__,__LINE__, (x)->module, \ + (x), (x)->owner, (x)->oline); \ + (x)->babble--; \ + } \ + 0; \ + }) + +/* without debugging, spin_trylock on UP always says + * TRUE. --> printk if already locked. */ +#define spin_trylock(x) \ + ({ \ + if ((x)->lock&&(x)->babble) { \ + printk("%s:%d: spin_trylock(%s:%p) already locked by %s/%d\n", \ + __BASE_FILE__,__LINE__, (x)->module, \ + (x), (x)->owner, (x)->oline); \ + (x)->babble--; \ + } \ + (x)->lock = 1; \ + (x)->owner = __BASE_FILE__; \ + (x)->oline = __LINE__; \ + 1; \ + }) + +#define spin_lock(x) \ + do { \ + if ((x)->lock&&(x)->babble) { \ + printk("%s:%d: spin_lock(%s:%p) already locked by %s/%d\n", \ + __BASE_FILE__,__LINE__, (x)->module, \ + (x), (x)->owner, (x)->oline); \ + (x)->babble--; \ + } \ + (x)->lock = 1; \ + (x)->owner = __BASE_FILE__; \ + (x)->oline = __LINE__; \ + } while (0) + +#define spin_unlock_wait(x) \ + do { \ + if ((x)->lock&&(x)->babble) { \ + printk("%s:%d: spin_unlock_wait(%s:%p) owned by %s/%d\n", \ + __BASE_FILE__,__LINE__, (x)->module, (x), \ + (x)->owner, (x)->oline); \ + (x)->babble--; \ + }\ + } while (0) +#define spin_unlock(x) \ + do { \ + if (!(x)->lock&&(x)->babble) { \ + printk("%s:%d: spin_unlock(%s:%p) not locked\n", \ + __BASE_FILE__,__LINE__, (x)->module, (x));\ + (x)->babble--; \ + } \ + (x)->lock = 0; \ + } while (0) #endif /* DEBUG_SPINLOCKS */ --- 2.4/kernel/ksyms.c Sun Sep 23 21:20:55 2001 +++ build-2.4/kernel/ksyms.c Sun Sep 30 17:07:53 2001 @@ -376,10 +376,12 @@ EXPORT_SYMBOL(tq_timer); EXPORT_SYMBOL(tq_immediate); -#ifdef CONFIG_SMP +#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK_UP) /* Various random spinlocks we want to export */ EXPORT_SYMBOL(tqueue_lock); +#endif +#ifdef CONFIG_SMP /* Big-Reader lock implementation */ EXPORT_SYMBOL(__brlock_array); #ifndef __BRLOCK_USE_ATOMICS - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/