summaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorJeremy Kerr <jk@ozlabs.org>2008-02-26 13:31:42 +1100
committerJeremy Kerr <jk@ozlabs.org>2008-02-27 18:47:53 +1100
commitd58831375d68a3bd39d5ebab9eca711fbb4ee108 (patch)
treea232a5cb9715a9a4740e21a4f0fc757e1286a7d0 /arch
parent61b36fc1f7d511132b1dd1422c29c7a8f26d77db (diff)
[POWERPC] spufs: fix context destruction during psmap fault
We have a small window where a spu context may be destroyed while we're servicing a page fault (from another thread) to the context's problem state mapping. After we up_read() the mmap_sem, it's possible that the context is destroyed by its owning thread, and so the later references to ctx are invalid. This can maifest as a deadlock on the (now free()-ed) context state mutex. This change adds a reference to the context before we release the mmap_sem, so that the context cannot be destroyed. Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/powerpc/platforms/cell/spufs/file.c12
1 files changed, 11 insertions, 1 deletions
diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c
index c66c3756970..f7a7e8635fb 100644
--- a/arch/powerpc/platforms/cell/spufs/file.c
+++ b/arch/powerpc/platforms/cell/spufs/file.c
@@ -367,6 +367,13 @@ static unsigned long spufs_ps_nopfn(struct vm_area_struct *vma,
return NOPFN_SIGBUS;
/*
+ * Because we release the mmap_sem, the context may be destroyed while
+ * we're in spu_wait. Grab an extra reference so it isn't destroyed
+ * in the meantime.
+ */
+ get_spu_context(ctx);
+
+ /*
* We have to wait for context to be loaded before we have
* pages to hand out to the user, but we don't want to wait
* with the mmap_sem held.
@@ -375,7 +382,7 @@ static unsigned long spufs_ps_nopfn(struct vm_area_struct *vma,
* hanged.
*/
if (spu_acquire(ctx))
- return NOPFN_REFAULT;
+ goto refault;
if (ctx->state == SPU_STATE_SAVED) {
up_read(&current->mm->mmap_sem);
@@ -391,6 +398,9 @@ static unsigned long spufs_ps_nopfn(struct vm_area_struct *vma,
if (!ret)
spu_release(ctx);
+
+refault:
+ put_spu_context(ctx);
return NOPFN_REFAULT;
}