[PATCH v4 next 5/9] locking/osq_lock: Avoid writing to node->next in the osq_lock() fast path
From: David Laight
Date: Mon Sep 07 2026 - 04:48:51 EST
osq_unlink_from_next() is called by osq_unlock() and when osq_lock() returns
false (lock not acquired).
osq_unlink_from_next() will either have done an explicit xchg(&node->next, NULL)
or a cmpxchg() that checked that node was lock->tail.
In both cases node->next will be NULL in exit.
Since it can't be changed when not referenced by an osq_lock there is no
need to initialise it at the top of osq_lock().
The atomic_xchg(&lock->tail, curr) could probably changed back to
the '_acquire' version or even the _relaxed version.
The important barrier is after the write to node->prev.
Defer determining the address of the CPU's 'node' until after the
atomic_exchange() so that it isn't done in the uncontented path.
Signed-off-by: David Laight <david.laight.linux@xxxxxxxxx>
---
kernel/locking/osq_lock.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/kernel/locking/osq_lock.c b/kernel/locking/osq_lock.c
index f39f77c3a07d..2f92d3d63da9 100644
--- a/kernel/locking/osq_lock.c
+++ b/kernel/locking/osq_lock.c
@@ -86,6 +86,9 @@ osq_unlink_from_next(struct optimistic_spin_queue *lock, int prev)
* We were the last queued, lock->tail now references
* prev (or is 0 if the list is now empty).
* If prev was spinning in this loop it can continue.
+ *
+ * Since we are the tail of the list, node->next
+ * must be NULL.
*/
return NULL;
}
@@ -122,13 +125,10 @@ osq_unlink_from_next(struct optimistic_spin_queue *lock, int prev)
bool osq_lock(struct optimistic_spin_queue *lock)
{
- struct optimistic_spin_node *node = this_cpu_ptr(&osq_node);
- struct optimistic_spin_node *prev_ptr, *next;
+ struct optimistic_spin_node *node, *prev_ptr, *next;
int curr = encode_cpu(smp_processor_id());
int prev;
- node->next = NULL;
-
/*
* We need both ACQUIRE (pairs with corresponding RELEASE in
* unlock() uncontended, or fastpath) and RELEASE (to publish
@@ -139,6 +139,7 @@ bool osq_lock(struct optimistic_spin_queue *lock)
if (prev == OSQ_UNLOCKED_VAL)
return true;
+ node = this_cpu_ptr(&osq_node);
prev_ptr = decode_cpu(prev);
node->prev = prev;
--
2.39.5