[PATCH 5/5] powerpc/spufs: fix mmap_lock/state_mutex lock inversion
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]> spufs_ps_fault() is called by the VM with mmap_lock held for read and takes ctx->state_mutex via spu_acquire(). When ctx->state is SPU_STATE_SAVED it drops mmap_lock, waits in spufs_wait() for the context to become runnable, and then re-takes mmap_lock. spufs_wait() returns with state_mutex re-acquired, and spu_release() only runs after the branch, so mmap_read_lock() is called while state_mutex is held. Every other spufs fault path takes the locks in the opposite order: spufs_mem_mmap_fault() and spufs_ps_fault() are entered with mmap_lock already held and only then take state_mutex. Three threads sharing an mm can close the cycle: one holds state_mutex and blocks in mmap_read_lock(), another holds mmap_lock for read and blocks in spu_acquire(), and a queued writer in mmap_write_lock() prevents the first down_read() from succeeding. This can result in a deadlock, and since spusched_tick() takes the same state_mutex, one wedged context also stalls SPU scheduling for every other context on the node. Fix by calling spu_release() before re-taking mmap_lock and jumping to the existing refault path, which drops the reference taken earlier in the function and returns VM_FAULT_NOPAGE as before. Fixes: 33bfd7a73861 ("[POWERPC] spufs: block fault handlers in spu_acquire_runnable") 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/file.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c index 07b1755ddc3d..d479c956506d 100644 --- a/arch/powerpc/platforms/cell/spufs/file.c +++ b/arch/powerpc/platforms/cell/spufs/file.c @@ -349,7 +349,10 @@ static vm_fault_t spufs_ps_fault(struct vm_fault *vmf, spu_context_nospu_trace(spufs_ps_fault__sleep, ctx); err = spufs_wait(ctx->run_wq, ctx->state == SPU_STATE_RUNNABLE); spu_context_trace(spufs_ps_fault__wake, ctx, ctx->spu); + if (!err) + spu_release(ctx); mmap_read_lock(current->mm); + goto refault; } else { area = ctx->spu->problem_phys + ps_offs; ret = vmf_insert_pfn(vmf->vma, vmf->address, -- 2.51.2