mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-09-04 20:19:47 +08:00
spufs: switch to locked_recursive_removal()
... and fix an old deadlock on spufs_mkdir() failures to populate subdirectory - spufs_rmdir() had always been taking lock on the victim, so doing it while the victim is locked is a bad idea. Reviewed-by: Christian Brauner <brauner@kernel.org> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
parent
9fd45235fd
commit
8c0e092e38
@ -143,42 +143,13 @@ spufs_evict_inode(struct inode *inode)
|
|||||||
put_spu_gang(ei->i_gang);
|
put_spu_gang(ei->i_gang);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void spufs_prune_dir(struct dentry *dir)
|
|
||||||
{
|
|
||||||
struct dentry *dentry;
|
|
||||||
struct hlist_node *n;
|
|
||||||
|
|
||||||
inode_lock(d_inode(dir));
|
|
||||||
hlist_for_each_entry_safe(dentry, n, &dir->d_children, d_sib) {
|
|
||||||
spin_lock(&dentry->d_lock);
|
|
||||||
if (simple_positive(dentry)) {
|
|
||||||
dget_dlock(dentry);
|
|
||||||
__d_drop(dentry);
|
|
||||||
spin_unlock(&dentry->d_lock);
|
|
||||||
simple_unlink(d_inode(dir), dentry);
|
|
||||||
/* XXX: what was dcache_lock protecting here? Other
|
|
||||||
* filesystems (IB, configfs) release dcache_lock
|
|
||||||
* before unlink */
|
|
||||||
dput(dentry);
|
|
||||||
} else {
|
|
||||||
spin_unlock(&dentry->d_lock);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
shrink_dcache_parent(dir);
|
|
||||||
inode_unlock(d_inode(dir));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Caller must hold parent->i_mutex */
|
/* Caller must hold parent->i_mutex */
|
||||||
static int spufs_rmdir(struct inode *parent, struct dentry *dir)
|
static void spufs_rmdir(struct inode *parent, struct dentry *dir)
|
||||||
{
|
{
|
||||||
/* remove all entries */
|
struct spu_context *ctx = SPUFS_I(d_inode(dir))->i_ctx;
|
||||||
int res;
|
|
||||||
spufs_prune_dir(dir);
|
locked_recursive_removal(dir, NULL);
|
||||||
d_drop(dir);
|
spu_forget(ctx);
|
||||||
res = simple_rmdir(parent, dir);
|
|
||||||
/* We have to give up the mm_struct */
|
|
||||||
spu_forget(SPUFS_I(d_inode(dir))->i_ctx);
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int spufs_fill_dir(struct dentry *dir,
|
static int spufs_fill_dir(struct dentry *dir,
|
||||||
@ -222,15 +193,13 @@ static int spufs_dir_close(struct inode *inode, struct file *file)
|
|||||||
{
|
{
|
||||||
struct inode *parent;
|
struct inode *parent;
|
||||||
struct dentry *dir;
|
struct dentry *dir;
|
||||||
int ret;
|
|
||||||
|
|
||||||
dir = file->f_path.dentry;
|
dir = file->f_path.dentry;
|
||||||
parent = d_inode(dir->d_parent);
|
parent = d_inode(dir->d_parent);
|
||||||
|
|
||||||
inode_lock_nested(parent, I_MUTEX_PARENT);
|
inode_lock_nested(parent, I_MUTEX_PARENT);
|
||||||
ret = spufs_rmdir(parent, dir);
|
spufs_rmdir(parent, dir);
|
||||||
inode_unlock(parent);
|
inode_unlock(parent);
|
||||||
WARN_ON(ret);
|
|
||||||
|
|
||||||
unuse_gang(dir->d_parent);
|
unuse_gang(dir->d_parent);
|
||||||
return dcache_dir_close(inode, file);
|
return dcache_dir_close(inode, file);
|
||||||
@ -288,11 +257,11 @@ spufs_mkdir(struct inode *dir, struct dentry *dentry, unsigned int flags,
|
|||||||
ret = spufs_fill_dir(dentry, spufs_dir_debug_contents,
|
ret = spufs_fill_dir(dentry, spufs_dir_debug_contents,
|
||||||
mode, ctx);
|
mode, ctx);
|
||||||
|
|
||||||
|
inode_unlock(inode);
|
||||||
|
|
||||||
if (ret)
|
if (ret)
|
||||||
spufs_rmdir(dir, dentry);
|
spufs_rmdir(dir, dentry);
|
||||||
|
|
||||||
inode_unlock(inode);
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -475,7 +444,7 @@ spufs_create_context(struct inode *inode, struct dentry *dentry,
|
|||||||
|
|
||||||
ret = spufs_context_open(&path);
|
ret = spufs_context_open(&path);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
WARN_ON(spufs_rmdir(inode, dentry));
|
spufs_rmdir(inode, dentry);
|
||||||
|
|
||||||
out_aff_unlock:
|
out_aff_unlock:
|
||||||
if (affinity)
|
if (affinity)
|
||||||
|
Loading…
Reference in New Issue
Block a user