mirror of https://gitee.com/openkylin/linux.git
[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: Michael Ellerman <michael@ellerman.id.au> Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com> Signed-off-by: Paul Mackerras <paulus@samba.org>
This commit is contained in:
parent
d9379c4bce
commit
0309f02d8e
|
@ -157,20 +157,12 @@ static void spufs_prune_dir(struct dentry *dir)
|
||||||
mutex_unlock(&dir->d_inode->i_mutex);
|
mutex_unlock(&dir->d_inode->i_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Caller must hold root->i_mutex */
|
||||||
static int spufs_rmdir(struct inode *root, struct dentry *dir_dentry)
|
static int spufs_rmdir(struct inode *root, struct dentry *dir_dentry)
|
||||||
{
|
{
|
||||||
struct spu_context *ctx;
|
|
||||||
|
|
||||||
/* remove all entries */
|
/* remove all entries */
|
||||||
mutex_lock(&root->i_mutex);
|
|
||||||
spufs_prune_dir(dir_dentry);
|
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);
|
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)
|
static int spufs_dir_close(struct inode *inode, struct file *file)
|
||||||
{
|
{
|
||||||
|
struct spu_context *ctx;
|
||||||
struct inode *dir;
|
struct inode *dir;
|
||||||
struct dentry *dentry;
|
struct dentry *dentry;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
dentry = file->f_dentry;
|
dentry = file->f_dentry;
|
||||||
dir = dentry->d_parent->d_inode;
|
dir = dentry->d_parent->d_inode;
|
||||||
|
ctx = SPUFS_I(dentry->d_inode)->i_ctx;
|
||||||
|
|
||||||
|
mutex_lock(&dir->i_mutex);
|
||||||
ret = spufs_rmdir(dir, dentry);
|
ret = spufs_rmdir(dir, dentry);
|
||||||
|
mutex_unlock(&dir->i_mutex);
|
||||||
WARN_ON(ret);
|
WARN_ON(ret);
|
||||||
|
|
||||||
|
/* We have to give up the mm_struct */
|
||||||
|
spu_forget(ctx);
|
||||||
|
|
||||||
return dcache_dir_close(inode, file);
|
return dcache_dir_close(inode, file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -324,8 +323,13 @@ long spufs_create_thread(struct nameidata *nd,
|
||||||
* in error path of *_open().
|
* in error path of *_open().
|
||||||
*/
|
*/
|
||||||
ret = spufs_context_open(dget(dentry), mntget(nd->mnt));
|
ret = spufs_context_open(dget(dentry), mntget(nd->mnt));
|
||||||
if (ret < 0)
|
if (ret < 0) {
|
||||||
spufs_rmdir(nd->dentry->d_inode, dentry);
|
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:
|
out_dput:
|
||||||
dput(dentry);
|
dput(dentry);
|
||||||
|
|
Loading…
Reference in New Issue