[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