Subject: allow spufs nopfn functions to be interrupted From: Arnd Bergmann This turns the context acquire function in the nopfn handlers for spufs ps and ls pages, so that we can kill the tasks if something goes wrong. In particular, it allows us to recover from a nasty deadlock that happens when an SPU gets a page fault during a DMA it does to its own local store. One possible problem is how this interacts with copy_{from,to}_user to these pages, combined with a signal. It probably means that the kernel treats this as a fault returned from a system call, which potentially kills an innocent process. Signed-off-by: Arnd Bergmann Index: linux-2.6/arch/powerpc/platforms/cell/spufs/file.c =================================================================== --- linux-2.6.orig/arch/powerpc/platforms/cell/spufs/file.c +++ linux-2.6/arch/powerpc/platforms/cell/spufs/file.c @@ -129,7 +129,8 @@ static unsigned long spufs_mem_mmap_nopf pr_debug("spufs_mem_mmap_nopfn address=0x%lx -> 0x%lx, offset=0x%lx\n", addr0, address, offset); - spu_acquire(ctx); + if (spu_acquire_interruptible(ctx)) + return NOPFN_REFAULT; if (ctx->state == SPU_STATE_SAVED) { vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) Index: linux-2.6/arch/powerpc/platforms/cell/spufs/context.c =================================================================== --- linux-2.6.orig/arch/powerpc/platforms/cell/spufs/context.c +++ linux-2.6/arch/powerpc/platforms/cell/spufs/context.c @@ -170,9 +170,13 @@ int spu_acquire_exclusive(struct spu_con */ int spu_acquire_runnable(struct spu_context *ctx, unsigned long flags) { - int ret = -EINVAL; + int ret; - spu_acquire(ctx); + ret = spu_acquire_interruptible(ctx); + if (ret) + return ret; + + ret = -EINVAL; if (ctx->state == SPU_STATE_SAVED) { /* * Context is about to be freed, so we can't acquire it anymore. Index: linux-2.6/arch/powerpc/platforms/cell/spufs/spufs.h =================================================================== --- linux-2.6.orig/arch/powerpc/platforms/cell/spufs/spufs.h +++ linux-2.6/arch/powerpc/platforms/cell/spufs/spufs.h @@ -197,6 +197,11 @@ static inline void spu_acquire(struct sp mutex_lock(&ctx->state_mutex); } +static inline int spu_acquire_interruptible(struct spu_context *ctx) +{ + return mutex_lock_interruptible(&ctx->state_mutex); +} + static inline void spu_release(struct spu_context *ctx) { mutex_unlock(&ctx->state_mutex);