Message ID | 20240829022830.1164355-1-nysal@linux.ibm.com (mailing list archive) |
---|---|
State | Accepted |
Commit | 734ad0af3609464f8f93e00b6c0de1e112f44559 |
Headers | show |
Series | [v2] powerpc/qspinlock: Fix deadlock in MCS queue | expand |
Context | Check | Description |
---|---|---|
snowpatch_ozlabs/github-powerpc_ppctests | success | Successfully ran 8 jobs. |
snowpatch_ozlabs/github-powerpc_selftests | success | Successfully ran 8 jobs. |
snowpatch_ozlabs/github-powerpc_sparse | success | Successfully ran 4 jobs. |
snowpatch_ozlabs/github-powerpc_clang | success | Successfully ran 5 jobs. |
snowpatch_ozlabs/github-powerpc_kernel_qemu | success | Successfully ran 21 jobs. |
On Thu, 29 Aug 2024 07:58:27 +0530, Nysal Jan K.A. wrote: > If an interrupt occurs in queued_spin_lock_slowpath() after we increment > qnodesp->count and before node->lock is initialized, another CPU might > see stale lock values in get_tail_qnode(). If the stale lock value happens > to match the lock on that CPU, then we write to the "next" pointer of > the wrong qnode. This causes a deadlock as the former CPU, once it becomes > the head of the MCS queue, will spin indefinitely until it's "next" pointer > is set by its successor in the queue. > > [...] Applied to powerpc/fixes. [1/1] powerpc/qspinlock: Fix deadlock in MCS queue https://git.kernel.org/powerpc/c/734ad0af3609464f8f93e00b6c0de1e112f44559 cheers
diff --git a/arch/powerpc/lib/qspinlock.c b/arch/powerpc/lib/qspinlock.c index 5de4dd549f6e..bcc7e4dff8c3 100644 --- a/arch/powerpc/lib/qspinlock.c +++ b/arch/powerpc/lib/qspinlock.c @@ -697,7 +697,15 @@ static __always_inline void queued_spin_lock_mcs_queue(struct qspinlock *lock, b } release: - qnodesp->count--; /* release the node */ + /* + * Clear the lock before releasing the node, as another CPU might see stale + * values if an interrupt occurs after we increment qnodesp->count + * but before node->lock is initialized. The barrier ensures that + * there are no further stores to the node after it has been released. + */ + node->lock = NULL; + barrier(); + qnodesp->count--; } void queued_spin_lock_slowpath(struct qspinlock *lock)