[PATCH 4/5] powerpc/spufs: fix context state race in spu_acquire_saved()

Junrui Luo via B4 Relay <[email protected]>
Newsgroups org.ozlabs.lists.linuxppc-dev,org.kernel.feeds.b4-sent,org.kernel.vger.linux-kernel,org.kernel.vger.stable
Message-ID <[email protected]>
From: Junrui Luo <[email protected]>

spu_acquire_saved() returns with ctx->state_mutex held and the context
in SPU_STATE_SAVED.  It tests ctx->state once and, if the context is
still running, sets SPU_SCHED_WAS_ACTIVE and calls spu_deactivate().
That path reaches __spu_deactivate(ctx, 1, MAX_PRIO), which drops
state_mutex around spu_schedule() once spu_unschedule() has unbound the
context, so the test result is stale by the time the function returns.

A second thread reading any saved-state file of the same context can
take state_mutex in that window, observe SPU_STATE_SAVED and skip its
own deactivate.  SPU_SCHED_WAS_ACTIVE is a single bit in
ctx->sched_flags rather than a per-acquirer token, so that thread's
spu_release_saved() consumes the bit and calls spu_activate(), binding
the context back onto an SPU.  The first thread then returns from
spu_acquire_saved() with the context RUNNABLE, reads a save image the
SPU is concurrently writing, and trips the
BUG_ON(ctx->state != SPU_STATE_SAVED) in its own spu_release_saved(),
leaving state_mutex held.

Fix by retesting the state after spu_deactivate() returns, which also
re-sets SPU_SCHED_WAS_ACTIVE so the acquirer keeps its own reactivation
token.

Fixes: e65c2f6fcebb ("[POWERPC] spufs: decouple spu scheduler from spufs_spu_run (asynchronous scheduling)")
Reported-by: Yuhao Jiang <[email protected]>
Assisted-by: Claude:claude-opus-5
Cc: [email protected]
Signed-off-by: Junrui Luo <[email protected]>
---
Found by inspection; I have no Cell/PS3 hardware, so this is
compile-tested only.
---
 arch/powerpc/platforms/cell/spufs/context.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/powerpc/platforms/cell/spufs/context.c b/arch/powerpc/platforms/cell/spufs/context.c
index 44377dfff1f8..2414ad9be0ae 100644
--- a/arch/powerpc/platforms/cell/spufs/context.c
+++ b/arch/powerpc/platforms/cell/spufs/context.c
@@ -107,7 +107,7 @@ void spu_forget(struct spu_context *ctx)
 	 * want this context to be rescheduled on release.
 	 */
 	mutex_lock(&ctx->state_mutex);
-	if (ctx->state != SPU_STATE_SAVED)
+	while (ctx->state != SPU_STATE_SAVED)
 		spu_deactivate(ctx);
 
 	mm = ctx->owner;
@@ -150,7 +150,7 @@ int spu_acquire_saved(struct spu_context *ctx)
 	if (ret)
 		return ret;
 
-	if (ctx->state != SPU_STATE_SAVED) {
+	while (ctx->state != SPU_STATE_SAVED) {
 		set_bit(SPU_SCHED_WAS_ACTIVE, &ctx->sched_flags);
 		spu_deactivate(ctx);
 	}

-- 
2.51.2
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.