Skip to content

Commit

Permalink
[POWERPC] spufs: fix deadlock in spu_create error path
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Michael Ellerman authored and Paul Mackerras committed Jun 21, 2006
1 parent d9379c4 commit 0309f02
Showing 1 changed file with 15 additions and 11 deletions.
26 changes: 15 additions & 11 deletions arch/powerpc/platforms/cell/spufs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down Expand Up @@ -199,16 +191,23 @@ static int spufs_fill_dir(struct dentry *dir, struct tree_descr *files,

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);
}

Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit 0309f02

Please sign in to comment.