* [PATCH v2] locking/osq_lock: Ensure proper locking semantics for osq_lock/osq_unlock()
@ 2026-09-14 20:15 Waiman Long
0 siblings, 0 replies; only message in thread
From: Waiman Long @ 2026-09-14 20:15 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Will Deacon, Boqun Feng
Cc: linux-kernel, Davidlohr Bueso, Haakon Bugge, David Laight,
Linus Torvalds, Yafang Shao, Steven Rostedt, Waiman Long
The osq_lock is special in the sense that lock transfer from one CPU to
the next can happen either over the common optimistic_spin_queue.tail
value with uncontended lock or over a lock waiter's own percpu
optimistic_spin_node.locked flag when the lock is contended.
To ensure proper lock synchronization, we need to provide
the acquire/release semantics for the osq_lock/osq_unlock()
functions in both cases. This is currently the case for the
common optimistic_spin_queue.tail value, but not for the percpu
optimistic_spin_node.locked flag as the proper barriers can be missing.
The "node->locked" read in osq_lock() was relaxed by commit 036cc30c6b6a
("locking/osq: No need for load/acquire when acquire-polling") a while
ago as the smp_load_acquire() loop was causing a performance hit due to
the repeated acquire barriers in the loop and it argued that an earlier
atomic_xchg() call could provide the needed barrier and reordering
wasn't a problem in the way osq_lock is being used by mutex and rwsem
for queuing purpose only. That atomic_xchg() barrier does not work
as a proper acquire barrier for osq_lock() if the lock hasn't been
acquired or isn't ready to be acquired when the barrier ends. So an
acquire barrier is still needed in order to have proper locking semantics.
The performance impact stated in that patch is due to repeated issuance
of acquire barrier which can be expensive depending on the architectures
and the actual processor used. It was not clear what machine and what
benchmark was being used to produce the performance data. Anyway, with
the new smp_cond_load_acquire() helper, only one acquire barrier is
issued at the end of the loop. So even if there is a performance impact,
it should be less than a repeating one.
As for the two percpu optimistic_spin_node.locked setting in osq_unlock(),
they are currently preceded by a full barrier xchg() call which can
provide the needed release barrier. Add comments saying that a release
barrier is needed for the proper functioning of the unlock operation
to alert people from accidentally remove the barrier when the code is
updated.
Fixes: 036cc30c6b6a ("locking/osq: No need for load/acquire when acquire-polling")
Tested-by: Håkon Bugge <haakon.bugge@oracle.com>
Signed-off-by: Waiman Long <longman@redhat.com>
---
kernel/locking/osq_lock.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
[v2] Reword the commit log and keep the WRITE_ONCE() in osq_unlock()
with comments.
diff --git a/kernel/locking/osq_lock.c b/kernel/locking/osq_lock.c
index b4233dc2c2b0..4fb63197f699 100644
--- a/kernel/locking/osq_lock.c
+++ b/kernel/locking/osq_lock.c
@@ -143,7 +143,7 @@ bool osq_lock(struct optimistic_spin_queue *lock)
* is implemented with a monitor-wait. vcpu_is_preempted() relies on
* polling, be careful.
*/
- if (smp_cond_load_relaxed(&node->locked, VAL || need_resched() ||
+ if (smp_cond_load_acquire(&node->locked, VAL || need_resched() ||
vcpu_is_preempted(node_cpu(node->prev))))
return true;
@@ -224,11 +224,17 @@ void osq_unlock(struct optimistic_spin_queue *lock)
node = this_cpu_ptr(&osq_node);
next = xchg(&node->next, NULL);
if (next) {
+ /* The xchg() call above provides the release barrier */
WRITE_ONCE(next->locked, 1);
return;
}
next = osq_wait_next(lock, node, OSQ_UNLOCKED_VAL);
- if (next)
+ if (next) {
+ /*
+ * The xchg() call in osq_wait_next() before a non-NULL return
+ * provides the release barrier.
+ */
WRITE_ONCE(next->locked, 1);
+ }
}
--
2.55.0
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2026-09-14 20:15 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-14 20:15 [PATCH v2] locking/osq_lock: Ensure proper locking semantics for osq_lock/osq_unlock() Waiman Long
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®