Re: spin_lock implicit/explicit memory barrier
From: Manfred Spraul
Date: Wed Aug 10 2016 - 14:21:33 EST
Hi,
[adding Peter, correcting Davidlohr's mail address]
On 08/10/2016 02:05 AM, Benjamin Herrenschmidt wrote:
On Tue, 2016-08-09 at 20:52 +0200, Manfred Spraul wrote:
Hi Benjamin, Hi Michael,
regarding commit 51d7d5205d33 ("powerpc: Add smp_mb() to
arch_spin_is_locked()"):
For the ipc/sem code, I would like to replace the spin_is_locked() with
a smp_load_acquire(), see:
http://git.cmpxchg.org/cgit.cgi/linux-mmots.git/tree/ipc/sem.c#n367
http://www.ozlabs.org/~akpm/mmots/broken-out/ipc-semc-fix-complex_count-vs-simple-op-race.patch
To my understanding, I must now add a smp_mb(), otherwise it would be
broken on PowerPC:
The approach that the memory barrier is added into spin_is_locked()
doesn't work because the code doesn't use spin_is_locked().
Correct?
Right, otherwise you aren't properly ordered. The current powerpc locks provide
good protection between what's inside vs. what's outside the lock but not vs.
the lock *value* itself, so if, like you do in the sem code, use the lock
value as something that is relevant in term of ordering, you probably need
an explicit full barrier.
Adding Paul McKenney.
Just to be safe, let's write down all barrier pairs:
entry and exit, simple and complex, and switching simple to complex and
vice versa.
(@Davidlohr: Could you crosscheck, did I overlook a pair?)
1)
spin_lock/spin_unlock pair.
2)
||smp_load_acquire(&sma->complex_mode) and
|||smp_store_release(sma->complex_mode, true) pair.
||http://git.cmpxchg.org/cgit.cgi/linux-mmots.git/tree/ipc/sem.c#n374
http://git.cmpxchg.org/cgit.cgi/linux-mmots.git/tree/ipc/sem.c#n321 The
store_release guarantees that all data written by the complex_op syscall
is - after the load_acquire - visible by the simple_op syscall. 3)
smp_mb() [after spin_lock()] and |||smp_store_mb(sma->complex_mode, true) pair.
|http://git.cmpxchg.org/cgit.cgi/linux-mmots.git/tree/ipc/sem.c#n287
http://git.cmpxchg.org/cgit.cgi/linux-mmots.git/tree/ipc/sem.c#n372 This
are actually two pairs: - Writing the lock variable must observed by the
task that does spin_unlock_wait() - complex_mode must be observed by the
task that does the smp_load_acquire() 4) spin_unlock_wait() and
spin_unlock() pair
http://git.cmpxchg.org/cgit.cgi/linux-mmots.git/tree/ipc/sem.c#n291
http://git.cmpxchg.org/cgit.cgi/linux-mmots.git/tree/ipc/sem.c#n409 The
data from the simple op must be observed by the following complex op.
Right now, there is still an smp_rmb() in line 300: The control barrier
from the loop inside spin_unlock_wait() is upgraded to an acquire
barrier by an additional smp_rmb(). Is this smp_rmb() required? If I
understand commit 2c6100227116 ("locking/qspinlock: Fix
spin_unlock_wait() some more") right, with this commit qspinlock handle
this case without the smp_rmb(). What I don't know if powerpc is using
qspinlock already, or if powerpc works without the smp_rmb(). -- Manfred|