[tip: locking/core] locking/osq: Save the CPU number for 'prev', not the node address

From: tip-bot2 for David Laight

Date: Fri Nov 06 2026 - 05:26:57 EST


The following commit has been merged into the locking/core branch of tip:

Commit-ID: 72c440a4e225879063809c3d0bcdd7e6544069fe
Gitweb: https://git.kernel.org/tip/72c440a4e225879063809c3d0bcdd7e6544069fe
Author: David Laight <david.laight.linux@xxxxxxxxx>
AuthorDate: Mon, 07 Sep 2026 09:41:26 +01:00
Committer: Ingo Molnar <mingo@xxxxxxxxxx>
CommitterDate: Fri, 06 Nov 2026 11:16:24 +01:00

locking/osq: Save the CPU number for 'prev', not the node address

The CPU number of node->prev is needed for both the vcpu_is_preempted()
test and to update lock->tail. This saves reading the cache line for
the other CPU's per-CPU data.

The CPU member of optimistic_spin_node is no longer needed.

[ peterz: Renamed stuff ]

Signed-off-by: David Laight <david.laight.linux@xxxxxxxxx>
Signed-off-by: Peter Zijlstra (Intel) <peterz@xxxxxxxxxxxxx>
Signed-off-by: Ingo Molnar <mingo@xxxxxxxxxx>
Reviewed-by: Waiman Long <longman@xxxxxxxxxx>
Cc: Linus Torvalds <torvalds@xxxxxxxxxxxxxxxxxxxx>
Link: https://patch.msgid.link/20260907084133.3696-3-david.laight.linux@xxxxxxxxx
---
kernel/locking/osq_lock.c | 29 ++++++++++++-----------------
1 file changed, 12 insertions(+), 17 deletions(-)

diff --git a/kernel/locking/osq_lock.c b/kernel/locking/osq_lock.c
index 984fa11..ee1f69b 100644
--- a/kernel/locking/osq_lock.c
+++ b/kernel/locking/osq_lock.c
@@ -13,9 +13,9 @@
*/

struct optimistic_spin_node {
- struct optimistic_spin_node *next, *prev;
+ struct optimistic_spin_node *next;
int locked; /* 1 if lock acquired */
- int cpu; /* encoded CPU # + 1 value */
+ int prev_cpu; /* CPU number offset by 1 */
};

static DEFINE_PER_CPU_SHARED_ALIGNED(struct optimistic_spin_node, osq_node);
@@ -29,11 +29,6 @@ static inline int encode_cpu(int cpu_nr)
return cpu_nr + 1;
}

-static inline int node_cpu(struct optimistic_spin_node *node)
-{
- return node->cpu - 1;
-}
-
static inline struct optimistic_spin_node *decode_cpu(int encoded_cpu_val)
{
int cpu_nr = encoded_cpu_val - 1;
@@ -137,11 +132,10 @@ bool osq_lock(struct optimistic_spin_queue *lock)
struct optimistic_spin_node *node = this_cpu_ptr(&osq_node);
struct optimistic_spin_node *prev, *next;
int curr = encode_cpu(smp_processor_id());
- int old;
+ int prev_cpu;

node->locked = 0;
node->next = NULL;
- node->cpu = curr;

/*
* We need both ACQUIRE (pairs with corresponding RELEASE in
@@ -149,12 +143,12 @@ bool osq_lock(struct optimistic_spin_queue *lock)
* the node fields we just initialised) semantics when updating
* the lock tail.
*/
- old = atomic_xchg(&lock->tail, curr);
- if (old == OSQ_UNLOCKED_VAL)
+ prev_cpu = atomic_xchg(&lock->tail, curr);
+ if (prev_cpu == OSQ_UNLOCKED_VAL)
return true;

- prev = decode_cpu(old);
- node->prev = prev;
+ prev = decode_cpu(prev_cpu);
+ node->prev_cpu = prev_cpu;
osq_link_next(prev, node);

/*
@@ -173,7 +167,7 @@ bool osq_lock(struct optimistic_spin_queue *lock)
* polling, be careful.
*/
if (smp_cond_load_relaxed(&node->locked, VAL || need_resched() ||
- vcpu_is_preempted(node_cpu(node->prev))))
+ vcpu_is_preempted(node->prev_cpu - 1)))
return true;

/* unqueue */
@@ -208,7 +202,8 @@ bool osq_lock(struct optimistic_spin_queue *lock)
* Or we race against a concurrent unqueue()'s step-B, in which
* case its step-C will write us a new @node->prev pointer.
*/
- prev = READ_ONCE(node->prev);
+ prev_cpu = READ_ONCE(node->prev_cpu);
+ prev = decode_cpu(prev_cpu);
}

/*
@@ -218,7 +213,7 @@ bool osq_lock(struct optimistic_spin_queue *lock)
* back to @prev.
*/

- next = osq_wait_next(lock, node, prev->cpu);
+ next = osq_wait_next(lock, node, prev_cpu);
if (!next)
return false;

@@ -230,7 +225,7 @@ bool osq_lock(struct optimistic_spin_queue *lock)
* it will wait in Step-A.
*/

- WRITE_ONCE(next->prev, prev);
+ WRITE_ONCE(next->prev_cpu, prev_cpu);
osq_link_next(prev, next);

return false;