]> err.no Git - linux-2.6/commitdiff
[POWERPC] spufs: fix deadlock in spu_create error path
authorMichael Ellerman <michael@ellerman.id.au>
Mon, 19 Jun 2006 18:33:22 +0000 (20:33 +0200)
committerPaul Mackerras <paulus@samba.org>
Wed, 21 Jun 2006 05:01:30 +0000 (15:01 +1000)
spufs_rmdir tries to acquire the spufs root
i_mutex, which is already held by spufs_create_thread.

This was tracked as Bug #H9512.

Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>
Signed-off-by: Paul Mackerras <paulus@samba.org>
arch/powerpc/platforms/cell/spufs/inode.c

index d9554199afa744cb387aad3dd6db6beb3e6c20fb..fed511a2b17fbf344259158397c936299e053317 100644 (file)
@@ -157,20 +157,12 @@ static void spufs_prune_dir(struct dentry *dir)
        mutex_unlock(&dir->d_inode->i_mutex);
 }
 
+/* Caller must hold root->i_mutex */
 static int spufs_rmdir(struct inode *root, struct dentry *dir_dentry)
 {
-       struct spu_context *ctx;
-
        /* remove all entries */
-       mutex_lock(&root->i_mutex);
        spufs_prune_dir(dir_dentry);
-       mutex_unlock(&root->i_mutex);
 
-       /* We have to give up the mm_struct */
-       ctx = SPUFS_I(dir_dentry->d_inode)->i_ctx;
-       spu_forget(ctx);
-
-       /* XXX Do we need to hold i_mutex here ? */
        return simple_rmdir(root, dir_dentry);
 }
 
@@ -199,16 +191,23 @@ out:
 
 static int spufs_dir_close(struct inode *inode, struct file *file)
 {
+       struct spu_context *ctx;
        struct inode *dir;
        struct dentry *dentry;
        int ret;
 
        dentry = file->f_dentry;
        dir = dentry->d_parent->d_inode;
+       ctx = SPUFS_I(dentry->d_inode)->i_ctx;
 
+       mutex_lock(&dir->i_mutex);
        ret = spufs_rmdir(dir, dentry);
+       mutex_unlock(&dir->i_mutex);
        WARN_ON(ret);
 
+       /* We have to give up the mm_struct */
+       spu_forget(ctx);
+
        return dcache_dir_close(inode, file);
 }
 
@@ -324,8 +323,13 @@ long spufs_create_thread(struct nameidata *nd,
         * in error path of *_open().
         */
        ret = spufs_context_open(dget(dentry), mntget(nd->mnt));
-       if (ret < 0)
-               spufs_rmdir(nd->dentry->d_inode, dentry);
+       if (ret < 0) {
+               WARN_ON(spufs_rmdir(nd->dentry->d_inode, dentry));
+               mutex_unlock(&nd->dentry->d_inode->i_mutex);
+               spu_forget(SPUFS_I(dentry->d_inode)->i_ctx);
+               dput(dentry);
+               goto out;
+       }
 
 out_dput:
        dput(dentry);