[PATCH 5/5] powerpc/spufs: fix mmap_lock/state_mutex lock inversion

Junrui Luo via B4 Relay <[email protected]>
Newsgroups org.kernel.vger.stable,org.kernel.feeds.b4-sent,org.kernel.vger.linux-kernel,org.ozlabs.lists.linuxppc-dev
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
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.