Kernel fixes to spin_is_locked()
Subsystems (3)
cover Kernel fixes to spin_is_locked()
Hello!
This series contains fixes to the kernel related to the semantics of spin_is_locked(), all courtesy of Andrea Parri, and all ready for inclusion in -tip:
1. Document the semantics of spin_is_locked() by adding a docbook
header comment.
2. Remove smp_mb() from arch_spin_is_locked(), given that the
new order-free spin_is_locked() semantics require no such barrier.
3. Clean up comment and #ifndef for {,queued_}spin_is_locked().
The comment was "XXX think about spin_is_locked", and I can attest that we have now done some serious thinking. ;-)
Thanx, Paul
------------------------------------------------------------------------
PATCH 1/3 locking: Document the semantics of spin_is_locked()
From: Andrea Parri <[email protected]>
There appeared to be a certain, recurrent uncertainty concerning the semantics of spin_is_locked(), likely a consequence of the fact that this semantics remains undocumented or that it has been historically linked to the (likewise unclear) semantics of spin_unlock_wait().
A recent auditing [1] of the callers of the primitive confirmed that none of them are relying on particular ordering guarantees; document this semantics by adding a docbook header to spin_is_locked(). Also, describe behaviors specific to certain CONFIG_SMP=n builds.
[1] https://marc.info/?l=linux-kernel&m=151981440005264&w=2
https://marc.info/?l=linux-kernel&m=152042843808540&w=2 https://marc.info/?l=linux-kernel&m=152043346110262&w=2
--- include/linux/spinlock.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+)
include/linux/spinlock.h +18 -0
@@ -380,6 +380,24 @@ static __always_inline int spin_trylock_irq(spinlock_t *lock)raw_spin_trylock_irqsave (spinlock_check (lock), flags); \ }) +/** +* spin_is_locked() - Check whether a spinlock is locked. +* @lock: Pointer to the spinlock. +* +* This function is NOT required to provide any memory ordering +* guarantees; it could be used for debugging purposes or, when +* additional synchronization is needed, accompanied with other +* constructs (memory barriers) enforcing the synchronization. +* +* Returns: 1 if @lock is locked, 0 otherwise. +* +* Note that the function only tells you that the spinlock is +* seen to be locked, not that it is locked on your CPU. +* +* Further, on CONFIG_SMP=n builds with CONFIG_DEBUG_SPINLOCK=n, +* the return value is always 0 (see include/linux/spinlock_up.h). +* Therefore you should not rely heavily on the return value. +*/ static __always_inline int spin_is_locked(spinlock_t *lock) {return raw_spin_is_locked (&lock->rlock);
Signature · 1 line
2.5.2
tip-bot for Andrea Parri
merge bot[tip:locking/core] locking/spinlocks: Document the semantics of spin_is_locked()
locking/spinlocks: Document the semantics of spin_is_locked()
Commit-ID: b7e4aadef28f217de8907eec60a964328797a2be Gitweb: https://git.kernel.org/tip/b7e4aadef28f217de8907eec60a964328797a2be Author: Andrea Parri <[email protected]> AuthorDate: Mon, 14 May 2018 16:01:27 -0700 Committer: Ingo Molnar <[email protected]> CommitDate: Tue, 15 May 2018 08:11:15 +0200
locking/spinlocks: Document the semantics of spin_is_locked()
There appeared to be a certain, recurrent uncertainty concerning the semantics of spin_is_locked(), likely a consequence of the fact that this semantics remains undocumented or that it has been historically linked to the (likewise unclear) semantics of spin_unlock_wait().
A recent auditing [1] of the callers of the primitive confirmed that none of them are relying on particular ordering guarantees; document this semantics by adding a docbook header to spin_is_locked(). Also, describe behaviors specific to certain CONFIG_SMP=n builds.
[1] https://marc.info/?l=linux-kernel&m=151981440005264&w=2
https://marc.info/?l=linux-kernel&m=152042843808540&w=2 https://marc.info/?l=linux-kernel&m=152043346110262&w=2
--- include/linux/spinlock.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+)
include/linux/spinlock.h +18 -0
@@ -380,6 +380,24 @@ static __always_inline int spin_trylock_irq(spinlock_t *lock)raw_spin_trylock_irqsave (spinlock_check (lock), flags); \ }) +/** +* spin_is_locked() - Check whether a spinlock is locked. +* @lock: Pointer to the spinlock. +* +* This function is NOT required to provide any memory ordering +* guarantees; it could be used for debugging purposes or, when +* additional synchronization is needed, accompanied with other +* constructs (memory barriers) enforcing the synchronization. +* +* Returns: 1 if @lock is locked, 0 otherwise. +* +* Note that the function only tells you that the spinlock is +* seen to be locked, not that it is locked on your CPU. +* +* Further, on CONFIG_SMP=n builds with CONFIG_DEBUG_SPINLOCK=n, +* the return value is always 0 (see include/linux/spinlock_up.h). +* Therefore you should not rely heavily on the return value. +*/ static __always_inline int spin_is_locked(spinlock_t *lock) {return raw_spin_is_locked (&lock->rlock);
PATCH 2/3 arm64: Remove smp_mb() from arch_spin_is_locked()
In reply to Paul E. McKenneyFrom: Andrea Parri <[email protected]>
Commit 38b850a73034f ("arm64: spinlock: order spin_{is_locked,unlock_wait} against local locks") added an smp_mb() to arch_spin_is_locked(), in order "to ensure that the lock value is always loaded after any other locks have been taken by the current CPU", and reported one example (the "insane case" in ipc/sem.c) relying on such guarantee.
It is however understood that spin_is_locked() is not required to provide such an ordering guarantee (a guarantee that is currently not provided by all the implementations/archs), and that callers relying on such ordering should instead insert suitable memory barriers before acting on the result of spin_is_locked().
Following a recent auditing [1] of the callers of {,raw_}spin_is_locked(), revealing that none of them are relying on the ordering guarantee anymore, this commit removes the leading smp_mb() from the primitive thus reverting 38b850a73034f.
[1] https://marc.info/?l=linux-kernel&m=151981440005264&w=2
https://marc.info/?l=linux-kernel&m=152042843808540&w=2 https://marc.info/?l=linux-kernel&m=152043346110262&w=2
--- arch/arm64/include/asm/spinlock.h | 5 ----- 1 file changed, 5 deletions(-)
arch/arm64/include/asm/spinlock.h +0 -5
@@ -122,11 +122,6 @@ static inline int arch_spin_value_unlocked(arch_spinlock_t lock)static inline int arch_spin_is_locked (arch_spinlock_t *lock) { -/* -* Ensure prior spin_lock operations to other locks have completed -* on this CPU before we test whether "lock" is locked. -*/ -smp_mb ();/* ^^^ */ return !arch_spin_value_unlocked (READ_ONCE (*lock)); }
Signature · 1 line
2.5.2
tip-bot for Andrea Parri
merge bot[tip:locking/core] locking/spinlocks/arm64: Remove smp_mb() from arch_spin_is_locked()
locking/spinlocks/arm64: Remove smp_mb() from arch_spin_is_locked()
Commit-ID: c6f5d02b6a0fb91be5d656885ce02cf28952181d Gitweb: https://git.kernel.org/tip/c6f5d02b6a0fb91be5d656885ce02cf28952181d Author: Andrea Parri <[email protected]> AuthorDate: Mon, 14 May 2018 16:01:28 -0700 Committer: Ingo Molnar <[email protected]> CommitDate: Tue, 15 May 2018 08:11:15 +0200
locking/spinlocks/arm64: Remove smp_mb() from arch_spin_is_locked()
The following commit:
38b850a73034f ("arm64: spinlock: order spin_{is_locked,unlock_wait} against local locks")
... added an smp_mb() to arch_spin_is_locked(), in order
"to ensure that the lock value is always loaded after any other locks have been taken by the current CPU", and reported one example (the "insane case" in ipc/sem.c) relying on such guarantee.
It is however understood that spin_is_locked() is not required to provide such an ordering guarantee (a guarantee that is currently not provided by all the implementations/archs), and that callers relying on such ordering should instead insert suitable memory barriers before acting on the result of spin_is_locked().
Following a recent auditing [1] of the callers of {,raw_}spin_is_locked(), revealing that none of them are relying on the ordering guarantee anymore, this commit removes the leading smp_mb() from the primitive thus reverting 38b850a73034f.
[1] https://marc.info/?l=linux-kernel&m=151981440005264&w=2
https://marc.info/?l=linux-kernel&m=152042843808540&w=2 https://marc.info/?l=linux-kernel&m=152043346110262&w=2
--- arch/arm64/include/asm/spinlock.h | 5 ----- 1 file changed, 5 deletions(-)
arch/arm64/include/asm/spinlock.h +0 -5
@@ -122,11 +122,6 @@ static inline int arch_spin_value_unlocked(arch_spinlock_t lock)static inline int arch_spin_is_locked (arch_spinlock_t *lock) { -/* -* Ensure prior spin_lock operations to other locks have completed -* on this CPU before we test whether "lock" is locked. -*/ -smp_mb ();/* ^^^ */ return !arch_spin_value_unlocked (READ_ONCE (*lock)); }
PATCH 3/3 locking: Clean up comment and #ifndef for {,queued_}spin_is_locked()
In reply to Paul E. McKenneyFrom: Andrea Parri <[email protected]>
Removes "#ifndef queued_spin_is_locked" from the generic code: this is unused and it's reasonable to conclude that it will continue to be unused.
Also removes the comment about spin_is_locked() from mutex_is_locked():
the comment remains valid but not particularly useful.
--- include/asm-generic/qspinlock.h | 2 -- include/linux/mutex.h | 3 --- 2 files changed, 5 deletions(-)
include/asm-generic/qspinlock.h +0 -2
@@ -26,7 +26,6 @@* @lock: Pointer to queued spinlock structure * Return: 1 if it is locked, 0 otherwise */ -#ifndef queued_spin_is_locked static __always_inline int queued_spin_is_locked(struct qspinlock *lock) {/*
@@ -35,7 +34,6 @@ static __always_inline int queued_spin_is_locked(struct qspinlock *lock)*/ return atomic_read (&lock->val); } -#endif /** * queued_spin_value_unlocked - is the spinlock structure unlocked?
include/linux/mutex.h +0 -3
@@ -146,9 +146,6 @@ extern void __mutex_init(struct mutex *lock, const char *name,*/ static inline bool mutex_is_locked (struct mutex *lock) { -/* -* XXX think about spin_is_locked -*/ return __mutex_owner (lock) !=NULL ; }
Signature · 1 line
2.5.2
tip-bot for Andrea Parri
merge bot[tip:locking/core] locking/spinlocks: Clean up comment and #ifndef for {,queued_}spin_is_locked()
locking/spinlocks: Clean up comment and #ifndef for {,queued_}spin_is_locked()
Commit-ID: 1362ae43c503a4e333ab6948fc4c6e0e794e1558 Gitweb: https://git.kernel.org/tip/1362ae43c503a4e333ab6948fc4c6e0e794e1558 Author: Andrea Parri <[email protected]> AuthorDate: Mon, 14 May 2018 16:01:29 -0700 Committer: Ingo Molnar <[email protected]> CommitDate: Tue, 15 May 2018 08:11:15 +0200
locking/spinlocks: Clean up comment and #ifndef for {,queued_}spin_is_locked()
Removes "#ifndef queued_spin_is_locked" from the generic code: this is unused and it's reasonable to conclude that it will continue to be unused.
Also removes the comment about spin_is_locked() from mutex_is_locked():
the comment remains valid but not particularly useful.
--- include/asm-generic/qspinlock.h | 2 -- include/linux/mutex.h | 3 --- 2 files changed, 5 deletions(-)
include/asm-generic/qspinlock.h +0 -2
@@ -26,7 +26,6 @@* @lock: Pointer to queued spinlock structure * Return: 1 if it is locked, 0 otherwise */ -#ifndef queued_spin_is_locked static __always_inline int queued_spin_is_locked(struct qspinlock *lock) {/*
@@ -35,7 +34,6 @@ static __always_inline int queued_spin_is_locked(struct qspinlock *lock)*/ return atomic_read (&lock->val); } -#endif /** * queued_spin_value_unlocked - is the spinlock structure unlocked?
include/linux/mutex.h +0 -3
@@ -146,9 +146,6 @@ extern void __mutex_init(struct mutex *lock, const char *name,*/ static inline bool mutex_is_locked (struct mutex *lock) { -/* -* XXX think about spin_is_locked -*/ return __mutex_owner (lock) !=NULL ; }