Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0309f02d authored by Michael Ellerman's avatar Michael Ellerman Committed by Paul Mackerras
Browse files

[POWERPC] spufs: fix deadlock in spu_create error path



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: default avatarMichael Ellerman <michael@ellerman.id.au>
Signed-off-by: default avatarArnd Bergmann <arnd.bergmann@de.ibm.com>
Signed-off-by: default avatarPaul Mackerras <paulus@samba.org>
parent d9379c4b
Loading
Loading
Loading
Loading
+15 −11
Original line number Diff line number Diff line
@@ -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 @@ 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);
}

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