spinlock: __raw_spin_is_locked() should return true for UP
PATCH 1/1 spinlock: __raw_spin_is_locked() should return true for UP
For some reason __raw_spin_is_locked() has been returning false for the uni-processor, non-CONFIG_DEBUG_SPINLOCK. The UP + CONFIG_DEBUG_SPINLOCK handles this correctly.
Found this by enabling CONFIG_DEBUG_VM on PPC and hitting always hitting a BUG_ON that was testing to make sure the pte_lock was held.
---
Linus, a fix for 2.6.31
include/linux/spinlock_up.h | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
include/linux/spinlock_up.h +1 -1
@@ -57,7 +57,7 @@ static inline void __raw_spin_unlock(raw_spinlock_t *lock)#define __raw_write_unlock (lock) do { (void)(lock); } while (0)#else /* DEBUG_SPINLOCK */ -#define __raw_spin_is_locked (lock) ((void)(lock), 0) +#define __raw_spin_is_locked (lock) ((void)(lock), 1)/* for sched.c and kernel_lock.c: */ # define __raw_spin_lock (lock) do { (void)(lock); } while (0)# define __raw_spin_lock_flags (lock, flags) do { (void)(lock); } while (0)
Signature · 1 line
1.6.0.6
Quoted 5 lines · Kumar Gala
For some reason
__raw_spin_is_locked()has been returning false for the uni-processor, non-CONFIG_DEBUG_SPINLOCK. The UP +CONFIG_DEBUG_SPINLOCKhandles this correctly.
Quoted 7 lines
Found this by enabling
CONFIG_DEBUG_VMon PPC and hitting always hitting aBUG_ONthat was testing to make sure thepte_lockwas held.Signed-off-by Kumar Gala <[email protected]>---
Linus, a fix for 2.6.31
This really isn't all that clear.
The thing is, some people may assert that a lock is held, but others could easily be looping until it's not held using something like
while (spin_is_locked(lock)) cpu_relax();
so it's hard to tell whether it should return true or false in the case where spin-locking simply doesn't exist.
Linus
Quoted 16 lines · Linus Torvalds
Quoted 5 lines · Kumar Gala
For some reason
__raw_spin_is_locked()has been returning false for the uni-processor, non-CONFIG_DEBUG_SPINLOCK. The UP +CONFIG_DEBUG_SPINLOCKhandles this correctly.Quoted 7 lines
Found this by enabling
CONFIG_DEBUG_VMon PPC and hitting always hitting aBUG_ONthat was testing to make sure thepte_lockwas held.Signed-off-by Kumar Gala <[email protected]>---
Linus, a fix for 2.6.31
Quoted 7 lines
This really isn't all that clear.
The thing is, some people may assert that a lock is held, but others could easily be looping until it's not held using something like
while (spin_is_locked(lock)) cpu_relax();
Wouldn't something like that be really racey? And anyone doing such a thing had better have that code within an #ifdef CONFIG_SMP.
Quoted 3 lines
so it's hard to tell whether it should return true or false in the case where spin-locking simply doesn't exist.
Actually, I did have a case where I would use it and would expect a return of 0. That was in the experimental printk code to see if it was safe to wakeup the klogd. I once had a check of the current cpu runqueue lock is locked, and if it was, not to wake up klogd. I'm sure there's other cases like this as well.
Thinking about it, UP probably should have spin_is_locked always return false, but if you want to make sure you are not in a critical section with the lock not held, then use assert_spin_locked, which on UP should be a nop.
-- Steve
Quoted 9 lines · Steven Rostedt
Quoted 6 lines
The thing is, some people may assert that a lock is held, but others could easily be looping until it's not held using something like
while (spin_is_locked(lock)) cpu_relax();Wouldn't something like that be really racey? And anyone doing such a thing had better have that code within an #ifdef
CONFIG_SMP.
Sure, it's hopefully inside a #ifdef CONFIG_SMP.
And no, it's not necessarily racy. Sure, it's race in itself if that's all you are doing, but I could imagine writing that kind of code if I knew some lock was likely held, and I wanted to avoid doing a "try_lock()" until it got released.
The point is, "spin_is_locked()" is simply not a well-defined operation in this case. It could go either way.
And for the original case, we actually have a function for that:
assert_spin_locked(x)
which goes away on UP. Exactly because
BUG_ON(!spin_is_locked(x))
is not a good thing to do!
Quoted 8 lines
Quoted 2 lines
so it's hard to tell whether it should return true or false in the case where spin-locking simply doesn't exist.
Actually, I did have a case where I would use it and would expect a return of 0. That was in the experimental printk code to see if it was safe to wakeup the klogd. I once had a check of the current cpu runqueue lock is locked, and if it was, not to wake up klogd. I'm sure there's other cases like this as well.
Yeah, "spin_is_locked()" can be useful for those kinds of things. A heuristic for whether we should do something based on whether some other CPU holds it (or we migth have recursion).
Exactly like it can be useful for doing the BUG_ON thing. But in both cases it's a bit iffy.
Quoted 4 lines
Thinking about it, UP probably should have
spin_is_lockedalways return false, but if you want to make sure you are not in a critical section with the lock not held, then useassert_spin_locked, which on UP should be a nop.
That's what we do. That said, I also think we should generally try to avoid the kind of code that depends on spin_is_locked always returning false, for the same reason we should try to avoid any code that depends on it always returning true.
Linus
Quoted 10 lines · Linus Torvalds
Quoted 5 lines
Thinking about it, UP probably should have
spin_is_lockedalways return false, but if you want to make sure you are not in a critical section with the lock not held, then useassert_spin_locked, which on UP should be a nop.That's what we do. That said, I also think we should generally try to avoid the kind of code that depends on
spin_is_lockedalways returning false, for the same reason we should try to avoid any code that depends on it always returning true.
Perhaps we can deprecate spin_is_locked and replace it with "expect_spin_locked" and "expect_spin_unlocked" which on SMP would return true and false respectively if the lock was locked. But both would always return true on UP.
Or do some thing similar, that would remove the ambiguity on UP.
-- Steve
Quoted 12 lines · Steven Rostedt
Quoted 10 lines · Linus Torvalds
Quoted 5 lines
Thinking about it, UP probably should have
spin_is_lockedalways return false, but if you want to make sure you are not in a critical section with the lock not held, then useassert_spin_locked, which on UP should be a nop.That's what we do. That said, I also think we should generally try to avoid the kind of code that depends on
spin_is_lockedalways returning false, for the same reason we should try to avoid any code that depends on it always returning true.
Quoted 6 lines
Perhaps we can deprecate
spin_is_lockedand replace it with "expect_spin_locked" and "expect_spin_unlocked" which on SMP would return true and false respectively if the lock was locked. But both would always return true on UP.Or do some thing similar, that would remove the ambiguity on UP.
I agree its a little too easy to abuse spin_is_locked. However we should be consistent between spin_is_locked on UP between with and without CONFIG_DEBUG_SPINLOCK enabled. How much of this do we want to try and address in .31?
The PPC test really should be using assert_spin_locked and I'll send a patch to Ben for that.
- k
Quoted 4 lines · Kumar Gala
I agree its a little too easy to abuse
spin_is_locked. However we should be consistent betweenspin_is_lockedon UP between with and withoutCONFIG_DEBUG_SPINLOCKenabled.
No we shouldn't.
With CONFIG_DEBUG_SPINLOCK, you have an actual lock variable for debugging purposes, so spin_is_locked() can clearly return a _valid_ answer, and should do so.
Without DEBUG_SPINLOCK, there isn't any answer to return.
So there's no way we can or should be consistent. In one case an answer exists, in another one the answer is meaningless and doesn't exist.
Quoted 1 line
How much of this do we want to try and address in .31?
Absolutely nothing.
Quoted 2 lines
The PPC test really should be using
assert_spin_lockedand I'll send a patch to Ben for that.
Yes, that's the correct fix.
Linus
Quoted 10 lines · Linus Torvalds
Quoted 4 lines · Kumar Gala
I agree its a little too easy to abuse
spin_is_locked. However we should be consistent betweenspin_is_lockedon UP between with and withoutCONFIG_DEBUG_SPINLOCKenabled.No we shouldn't.
Quoted 8 lines
With
CONFIG_DEBUG_SPINLOCK, you have an actual lock variable for debugging purposes, sospin_is_locked()can clearly return a _valid_ answer, and should do so.Without
DEBUG_SPINLOCK, there isn't any answer to return.So there's no way we can or should be consistent. In one case an answer exists, in another one the answer is meaningless and doesn't exist.
I always thought behaviour should be consistent between code with debugging on and code without. Otherwise you may end up with cases of "it starts working when I turn on debugging" which are a pain to fix. Has something changed?
Or in other words, do you think lockdep should try solving deadlocks instead of just reporting them for instance?
OG.
Peter Zijlstra
maintainerQuoted 20 lines · Olivier Galibert
Quoted 10 lines · Linus Torvalds
Quoted 4 lines · Kumar Gala
I agree its a little too easy to abuse
spin_is_locked. However we should be consistent betweenspin_is_lockedon UP between with and withoutCONFIG_DEBUG_SPINLOCKenabled.No we shouldn't.
Quoted 8 lines
With
CONFIG_DEBUG_SPINLOCK, you have an actual lock variable for debugging purposes, sospin_is_locked()can clearly return a _valid_ answer, and should do so.Without
DEBUG_SPINLOCK, there isn't any answer to return.So there's no way we can or should be consistent. In one case an answer exists, in another one the answer is meaningless and doesn't exist.
Quoted 7 lines
I always thought behaviour should be consistent between code with debugging on and code without. Otherwise you may end up with cases of "it starts working when I turn on debugging" which are a pain to fix. Has something changed?
Or in other words, do you think lockdep should try solving deadlocks instead of just reporting them for instance?
The point is spin_is_locked() is a broken interface in that respect. Its plain impossible to give the right answer.
Suppose there's code doing:
/*
* Ensure we don't have foo lock taken, because that would cause
* lock inversion under bar lock.
*/
BUG_ON(spin_is_locked(&foo));
spin_lock(&bar);
and other code doing:
/* * Ensure we've got foo locked because it protects bar */ BUG_ON(!spin_is_locked(&foo)); bar = fancy;
What value should you return when locks don't exist (which is the case for UP)?
There simply is no right answer other than: don't use spin_is_locked().
Quoted 13 lines · Linus Torvalds
Quoted 9 lines · Steven Rostedt
Quoted 6 lines
The thing is, some people may assert that a lock is held, but others could easily be looping until it's not held using something like
while (spin_is_locked(lock)) cpu_relax();Wouldn't something like that be really racey? And anyone doing such a thing had better have that code within an #ifdef
CONFIG_SMP.
Quoted 6 lines
Sure, it's hopefully inside a #ifdef
CONFIG_SMP.And no, it's not necessarily racy. Sure, it's race in itself if that's all you are doing, but I could imagine writing that kind of code if I knew some lock was likely held, and I wanted to avoid doing a "
try_lock()" until it got released.
So you'd basically have the effect of a spin_lock(), except with the bonus of breaking RT hacks that do something other than spin, and preventing arch code from doing certain types of relaxation that are only appropriate when waiting on a lock (such as mdors on powerpc, which de-emphasizes until a reservation is broken).
Not exactly something we should encourage, IMHO.
-Scott