On Wed, 2012-03-07 at 14:49 +1100, Benjamin Herrenschmidt wrote:
> On Tue, 2012-03-06 at 10:26 +0100, masterzorag wrote:
> > I'm running my test program, it uses all available spus to compute via 
> > OpenCL
> > kernel 3.2.5 on a ps3
> > even on testing spu directly, it crashes
> 
> I think the patch is not 100% right yet. Looking at the code, we
> have a real mess of who gets to clean what up here. This is an
> attempt at sorting things by having the mutex and dentry dropped
> in spufs_create() always. Can you give it a spin (untested):
> 
> Al, I'm not familiar with the vfs, can you take a quick look ?

Better with the actual patch :-)

powerpc/cell: Fix locking in spufs_create()

The error path in spufs_create() could cause double unlocks
among other horrors. Clean it up.

Signed-off-by: Benjamin Herrenschmidt <b...@kernel.crashing.org>
Reported-by: masterzo...@gmail.com

diff --git a/arch/powerpc/platforms/cell/spufs/inode.c 
b/arch/powerpc/platforms/cell/spufs/inode.c
index d4a094c..63b4e43 100644
--- a/arch/powerpc/platforms/cell/spufs/inode.c
+++ b/arch/powerpc/platforms/cell/spufs/inode.c
@@ -454,19 +454,16 @@ spufs_create_context(struct inode *inode, struct dentry 
*dentry,
        struct spu_gang *gang;
        struct spu_context *neighbor;
 
-       ret = -EPERM;
        if ((flags & SPU_CREATE_NOSCHED) &&
-           !capable(CAP_SYS_NICE))
-               goto out_unlock;
+           !capable(CAP_SYa_NICE))
+               return -EPERM;
 
-       ret = -EINVAL;
        if ((flags & (SPU_CREATE_NOSCHED | SPU_CREATE_ISOLATE))
            == SPU_CREATE_ISOLATE)
-               goto out_unlock;
+               return -EINVAL;
 
-       ret = -ENODEV;
        if ((flags & SPU_CREATE_ISOLATE) && !isolated_loader)
-               goto out_unlock;
+               return -ENODEV;
 
        gang = NULL;
        neighbor = NULL;
@@ -512,10 +509,6 @@ spufs_create_context(struct inode *inode, struct dentry 
*dentry,
 out_aff_unlock:
        if (affinity)
                mutex_unlock(&gang->aff_mutex);
-out_unlock:
-       mutex_unlock(&inode->i_mutex);
-out:
-       dput(dentry);
        return ret;
 }
 
@@ -585,11 +578,9 @@ static int spufs_create_gang(struct inode *inode,
                        struct dentry *dentry,
                        struct vfsmount *mnt, umode_t mode)
 {
-       int ret;
-
-       ret = spufs_mkgang(inode, dentry, mode & S_IRWXUGO);
+       int ret = spufs_mkgang(inode, dentry, mode & S_IRWXUGO);
        if (ret)
-               goto out;
+               return ret;
 
        /*
         * get references for dget and mntget, will be released
@@ -600,10 +591,6 @@ static int spufs_create_gang(struct inode *inode,
                int err = simple_rmdir(inode, dentry);
                WARN_ON(err);
        }
-
-out:
-       mutex_unlock(&inode->i_mutex);
-       dput(dentry);
        return ret;
 }
 
@@ -613,22 +600,21 @@ static struct file_system_type spufs_type;
 long spufs_create(struct path *path, struct dentry *dentry,
                unsigned int flags, umode_t mode, struct file *filp)
 {
-       int ret;
+       int ret = -EINVAL;
 
-       ret = -EINVAL;
        /* check if we are on spufs */
        if (path->dentry->d_sb->s_type != &spufs_type)
-               goto out;
+               goto fail;
 
        /* don't accept undefined flags */
        if (flags & (~SPU_CREATE_FLAG_ALL))
-               goto out;
+               goto fail;
 
        /* only threads can be underneath a gang */
        if (path->dentry != path->dentry->d_sb->s_root) {
                if ((flags & SPU_CREATE_GANG) ||
                    !SPUFS_I(path->dentry->d_inode)->i_gang)
-                       goto out;
+               goto fail;
        }
 
        mode &= ~current_umask();
@@ -640,12 +626,17 @@ long spufs_create(struct path *path, struct dentry 
*dentry,
                ret = spufs_create_context(path->dentry->d_inode,
                                            dentry, path->mnt, flags, mode,
                                            filp);
-       if (ret >= 0)
+       if (ret >= 0) {
+               /* We drop these before fsnotify */
+               mutex_unlock(&inode->i_mutex);
+               dput(dentry);
                fsnotify_mkdir(path->dentry->d_inode, dentry);
-       return ret;
 
-out:
-       mutex_unlock(&path->dentry->d_inode->i_mutex);
+               return ret;
+       }
+ fail:
+       mutex_unlock(&inode->i_mutex);
+       dput(dentry);
        return ret;
 }
 
diff --git a/arch/powerpc/platforms/cell/spufs/syscalls.c 
b/arch/powerpc/platforms/cell/spufs/syscalls.c
index 8591bb6..1a65ef2 100644
--- a/arch/powerpc/platforms/cell/spufs/syscalls.c
+++ b/arch/powerpc/platforms/cell/spufs/syscalls.c
@@ -70,11 +70,8 @@ static long do_spu_create(const char __user *pathname, 
unsigned int flags,
        ret = PTR_ERR(dentry);
        if (!IS_ERR(dentry)) {
                ret = spufs_create(&path, dentry, flags, mode, neighbor);
-               mutex_unlock(&path.dentry->d_inode->i_mutex);
-               dput(dentry);
                path_put(&path);
        }
-
        return ret;
 }
 


_______________________________________________
Linuxppc-dev mailing list
Linuxppc-dev@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/linuxppc-dev

Reply via email to