lock assertion macros for 2.5.28
Subsystems (2)
PATCH 1/1 lock assertion macros for 2.5.28
Here's the lastest version of the lockassert patch. It includes:
o MUST_HOLD for all architectures
o MUST_HOLD_RW for architectures implementing rwlock_is_locked (only ia64 at the moment, as part of this patch)
o MUST_HOLD_RWSEM for arcitectures that use rwsem-spinlock.h
o MUST_HOLD_SEM for ia64
o a call to MUST_HOLD(&inode_lock) in inode.c:__iget().
I'd be happy to take patches that implement the above routines for other architectures and/or patches that sprinkle the macros where they're needed.
Thanks,
Jesse
fs/inode.c +2 -0
@@ -183,6 +183,8 @@*/ void __iget (struct inode * inode) { +MUST_HOLD (&inode_lock); +if (atomic_read (&inode->i_count)) {atomic_inc (&inode->i_count);return ;
include/asm-ia64/semaphore.h +7 -0
@@ -6,6 +6,7 @@* Copyright (C) 1998-2000 David Mosberger-Tang <[email protected]> */ +#include <linux/config.h> #include <linux/wait.h> #include <linux/rwsem.h>
@@ -24,6 +25,12 @@# define __SEM_DEBUG_INIT (name) , (long) &(name).__magic#else # define __SEM_DEBUG_INIT (name) +#endif + +#ifdef CONFIG_DEBUG_SPINLOCK +# define MUST_HOLD_SEM (sem) do { BUG_ON(atomic_read(sem->count)); } while(0); +#else +# define MUST_HOLD_SEM (sem) do { } while(0)#endif #define __SEMAPHORE_INITIALIZER (name,count) \
include/asm-ia64/spinlock.h +1 -0
@@ -109,6 +109,7 @@#define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0 }#define rwlock_init (x) do { *(x) = RW_LOCK_UNLOCKED; } while(0) +#define rwlock_is_locked (x) ((x)->read_counter != 0 || (x)->write_lock != 0)#define _raw_read_lock (rw) \ do { \
include/linux/rwsem-spinlock.h +6 -0
@@ -46,6 +46,12 @@#define __RWSEM_DEBUG_INIT/* */ #endif +#ifdef CONFIG_DEBUG_SPINLOCK +#define MUST_HOLD_RWSEM (sem) BUG_ON(!sem->activity)) +#else +#define MUST_HOLD_RWSEM (sem) do { } while (0) +#endif +#define __RWSEM_INITIALIZER (name) \ { 0, SPIN_LOCK_UNLOCKED, LIST_HEAD_INIT((name).wait_list) __RWSEM_DEBUG_INIT }
include/linux/rwsem.h +1 -0
@@ -7,6 +7,7 @@#ifndef _LINUX_RWSEM_H#define _LINUX_RWSEM_H +#include <linux/config.h> #include <linux/linkage.h> #define RWSEM_DEBUG 0
include/linux/spinlock.h +13 -1
@@ -117,7 +117,19 @@#define _raw_write_lock (lock) (void)(lock)/* Not "unused variable". */ #define _raw_write_unlock (lock) do { } while(0) -#endif /* !SMP */ +#endif /* !CONFIG_SMP */ + +/* +* Simple lock assertions for debugging and documenting where locks need +* to be locked/unlocked. +*/ +#if defined(CONFIG_DEBUG_SPINLOCK ) && defined(CONFIG_SMP ) +#define MUST_HOLD (lock) BUG_ON(!spin_is_locked(lock)) +#define MUST_HOLD_RW (lock) BUG_ON(!rwlock_is_locked(lock)) +#else +#define MUST_HOLD (lock) do { } while(0) +#define MUST_HOLD_RW (lock) do { } while(0) +#endif /* CONFIG_DEBUG_SPINLOCK && CONFIG_SMP */ #ifdef CONFIG_PREEMPT
Quoted 11 lines · Jesse Barnes
Here's the lastest version of the lockassert patch. It includes:
oMUST_HOLDfor all architectures
oMUST_HOLD_RWfor architectures implementingrwlock_is_locked(only ia64 at the moment, as part of this patch)
oMUST_HOLD_RWSEMfor arcitectures that userwsem-spinlock.h
oMUST_HOLD_SEMfor ia64
o a call toMUST_HOLD(&inode_lock)in inode.c:__iget().I'd be happy to take patches that implement the above routines for other architectures and/or patches that sprinkle the macros where they're needed.
Well one one place? Every single implementation of the request_fn method from the request_queue_t needs to hold some
lock associated with the queue in question.
In fact you will find ASSERT_LOCK macros sparnkled through the scsi code already right now. BTW> ASSERT_HOLDS would sound a bit more familiar to some of us.
This minor issue asside I think that your idea is a good thing.
Quoted 9 lines · Marcin Dalecki
Well one one place? Every single implementation of the
request_fnmethod from therequest_queue_tneeds to hold some
lock associated with the queue in question.In fact you will find
ASSERT_LOCKmacros sparnkled through the scsi code already right now. BTW>ASSERT_HOLDSwould sound a bit more familiar to some of us.This minor issue asside I think that your idea is a good thing.
Thanks for the pointer. I'll change those assertions over in the next revision.
Jesse
Quoted 5 lines · Jesse Barnes
Quoted 4 lines · Marcin Dalecki
Well one one place? Every single implementation of the
request_fnmethod from therequest_queue_tneeds to hold some
lock associated with the queue in question.
Quoted 8 lines
Quoted 5 lines
In fact you will find
ASSERT_LOCKmacros sparnkled through the scsi code already right now. BTW>ASSERT_HOLDSwould sound a bit more familiar to some of us.This minor issue asside I think that your idea is a good thing.
Thanks for the pointer. I'll change those assertions over in the next revision.
The scsi version is not the same, it's going to need to be changed to this sensible version.
The original name is better and shorter. I doubt there is anybody who will not know immediately what MUST_HOLD(&lock) means.
Signature · 1 line
Daniel
Quoted 8 lines · Jesse Barnes
Here's the lastest version of the lockassert patch. It includes:
oMUST_HOLDfor all architectures
oMUST_HOLD_RWfor architectures implementingrwlock_is_locked(only ia64 at the moment, as part of this patch)
oMUST_HOLD_RWSEMfor arcitectures that userwsem-spinlock.h
oMUST_HOLD_SEMfor ia64
o a call toMUST_HOLD(&inode_lock)in inode.c:__iget().
Quoted 7 lines
I'd be happy to take patches that implement the above routines for other architectures and/or patches that sprinkle the macros where they're needed.
Thanks,
Jesse
Jesse,
In reiser4 we are looking forward to having a MUST_NOT_HOLD (i.e., spin_is_not_locked) assertion for kernel spinlocks. Do you know if any progress has been made in that direction?
We have implemented a user-level testing framework for our file system and we are already using a spin_is_not_locked() method, but these assertions are disabled when compiled into the kernel.
-josh
Quoted 3 lines · Joshua MacDonald
In reiser4 we are looking forward to having a
MUST_NOT_HOLD(i.e.,spin_is_not_locked) assertion for kernel spinlocks. Do you know if any progress has been made in that direction?
Well, I had that in one version of the patch, but people didn't think it would be useful. Maybe you'd like to check out Oliver's comments at http://marc.theaimsgroup.com/?l=linux-kernel&m=102644431806734&w=2
and respond? If there's demand for MUST_NOT_HOLD, I'd be happy to add it since it should be easy. But if you're using it to enforce lock ordering as Oliver suggests, then there are probably more robust solutions.
Thanks,
Jesse
Quoted 5 lines · Jesse Barnes
Quoted 3 lines · Joshua MacDonald
In reiser4 we are looking forward to having a
MUST_NOT_HOLD(i.e.,spin_is_not_locked) assertion for kernel spinlocks. Do you know if any progress has been made in that direction?
Quoted 7 lines
Well, I had that in one version of the patch, but people didn't think it would be useful. Maybe you'd like to check out Oliver's comments at http://marc.theaimsgroup.com/?l=linux-kernel&m=102644431806734&w=2
and respond? If there's demand forMUST_NOT_HOLD, I'd be happy to add it since it should be easy. But if you're using it to enforce lock ordering as Oliver suggests, then there are probably more robust solutions.
Why don't you just generalize the scsi version that already support this?
reinventing the wheel everywhere..
Quoted 14 lines · Christoph Hellwig
Quoted 5 lines · Jesse Barnes
Quoted 3 lines · Joshua MacDonald
In reiser4 we are looking forward to having a
MUST_NOT_HOLD(i.e.,spin_is_not_locked) assertion for kernel spinlocks. Do you know if any progress has been made in that direction?Quoted 7 lines
Well, I had that in one version of the patch, but people didn't think it would be useful. Maybe you'd like to check out Oliver's comments at http://marc.theaimsgroup.com/?l=linux-kernel&m=102644431806734&w=2
and respond? If there's demand forMUST_NOT_HOLD, I'd be happy to add it since it should be easy. But if you're using it to enforce lock ordering as Oliver suggests, then there are probably more robust solutions.
Quoted 3 lines
Why don't you just generalize the scsi version that already support this?
reinventing the wheel everywhere..
Well, I wouldn't go that far. The macros are really simple and implementing a MUST_NOT_HOLD should be easy too. It could also be done in a much more useful way than how ASSERT_LOCK works, by tracking where the locks where acquired for example.
Did you check out the thread above? Having ASSERT_LOCK(&lock, 0) doesn't seem that useful by itself. A lot of the scsi code does things like:
ASSERT_LOCK(&lock, 0); ... spin_lock(&lock);
What does that buy you? The suggestions for tracking where the lock was acquired (in the thread above) seem much more useful.
Thanks,
Jesse
Quoted 14 lines · Christoph Hellwig
Quoted 5 lines · Jesse Barnes
Quoted 3 lines · Joshua MacDonald
In reiser4 we are looking forward to having a
MUST_NOT_HOLD(i.e.,spin_is_not_locked) assertion for kernel spinlocks. Do you know if any progress has been made in that direction?Quoted 7 lines
Well, I had that in one version of the patch, but people didn't think it would be useful. Maybe you'd like to check out Oliver's comments at http://marc.theaimsgroup.com/?l=linux-kernel&m=102644431806734&w=2
and respond? If there's demand forMUST_NOT_HOLD, I'd be happy to add it since it should be easy. But if you're using it to enforce lock ordering as Oliver suggests, then there are probably more robust solutions.
Quoted 3 lines
Why don't you just generalize the scsi version that already support this?
reinventing the wheel everywhere..
The scsi version is stupid. It panics instead of oopses and it takes two parameters.
More like improving a wheel, having observed that it works better if its round.
Signature · 1 line
Daniel
Quoted 7 lines · Jesse Barnes
Well, I had that in one version of the patch, but people didn't think it would be useful. Maybe you'd like to check out Oliver's comments at http://marc.theaimsgroup.com/?l=linux-kernel&m=102644431806734&w=2
and respond? If there's demand forMUST_NOT_HOLD, I'd be happy to add it since it should be easy. But if you're using it to enforce lock ordering as Oliver suggests, then there are probably more robust solutions.
Two other suggestions you could implement are CAN_SLEEP and CANNOT_SLEEP. You can implement them via the preempt_count.
Even if CONFIG_PREEMPT is not set, you will get preempt_count values representing whether or not you are in an interrupt or softirq (and thus atomic and cannot sleep). If CONFIG_PREEMPT is set, you get a counter that represents exactly the atomicity of the code including locks held.
E.g.,
#define CAN_SLEEP do { \
assert(unlikely(!preempt_count())); \
} while (0)
#define CANNOT_SLEEP do { \
assert(unlikely(preempt_count())); \
} while (0)This works great because after the IRQ changes in 2.5.28, preempt_count is a universal "are we atomic" count.
Robert Love
Quoted 5 lines · Jesse Barnes
Quoted 3 lines · Joshua MacDonald
In reiser4 we are looking forward to having a
MUST_NOT_HOLD(i.e.,spin_is_not_locked) assertion for kernel spinlocks. Do you know if any progress has been made in that direction?
Quoted 8 lines
Well, I had that in one version of the patch, but people didn't think it would be useful. Maybe you'd like to check out Oliver's comments at http://marc.theaimsgroup.com/?l=linux-kernel&m=102644431806734&w=2
and respond? If there's demand forMUST_NOT_HOLD, I'd be happy to add it since it should be easy. But if you're using it to enforce lock ordering as Oliver suggests, then there are probably more robust solutions.
I read Oliver's comments and I do not fully agree. It is true that often the MUST_NOT_HOLD macro is used to assert that you are not about to attempt a recursive lock, which a debugging spinlock implementation would catch as soon as the recursive attempt is made. However, it is difficult to make a case against adding support for this kind of assertion since it has many possible uses.
It may be useful to catch a recursive spinlock attempt several stack frames before it actually happens, or to assert that an unusual calling convention such as "This function is called with the spinlock held and if it returns 0 the spinlock remains held, but if the function returns non-zero the spinlock is released". We have such a function in reiser4.
As for preventing deadlock, it is true that (as Oliver says) "Locking order is larger than functions and should be documented at the point of declaration of the locks." We have a mechanism in reiser4 which is not quite the same as Oliver outlined for making assertions about lock ordering. We maintain per-thread counts of each spinlock class and use those counts in a locking predicate that is applied before a lock of each class is taken.
So I agree that recursive locking should be checked as part of the debugging spin_lock() routine and that deadlock detection requires more general work, but the MUST_NOT_HOLD assertion is still useful in some contexts.
-josh