Skip to contentSkip to conversation

spinlock: __raw_spin_is_locked() should return true for UP

PATCH In review Kumar Gala 6 participants 10 messages Aug 18, 2009 – Aug 19, 2009 Locking primitives

lore
Share & tools
lore

Kumar Gala

author
#0 lore raw

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
index d4841ed..2b372e0 100644
@@ -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
#1 lore raw
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_SPINLOCK handles this correctly.

Quoted 7 lines

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

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

#2 lore raw
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_SPINLOCK handles this correctly.

Quoted 7 lines

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

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

#3 lore raw
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_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.

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

#4 lore raw
Quoted 10 lines · Linus Torvalds
Quoted 5 lines

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.

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.

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

author
#5 lore raw
Quoted 12 lines · Steven Rostedt
Quoted 10 lines · Linus Torvalds
Quoted 5 lines

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.

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.

Quoted 6 lines

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.

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

#6 lore raw
Quoted 4 lines · Kumar Gala

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.

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_locked and I'll send a patch to Ben for that.

Yes, that's the correct fix.

Linus

#7 lore raw
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 between spin_is_locked on UP between with and without CONFIG_DEBUG_SPINLOCK enabled.

No we shouldn't.

Quoted 8 lines

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.

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.

maintainer
#8 lore raw
Quoted 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 between spin_is_locked on UP between with and without CONFIG_DEBUG_SPINLOCK enabled.

No we shouldn't.

Quoted 8 lines

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 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().

#9 lore raw
In reply to Linus Torvalds
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