mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-09-18 22:14:16 +00: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
1 changed files with 9 additions and 40 deletions
|
@ -143,42 +143,13 @@ spufs_evict_inode(struct inode *inode)
|
|||
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 */
|
||||
static int spufs_rmdir(struct inode *parent, struct dentry *dir)
|
||||
static void spufs_rmdir(struct inode *parent, struct dentry *dir)
|
||||
{
|
||||
/* remove all entries */
|
||||
int res;
|
||||
spufs_prune_dir(dir);
|
||||
d_drop(dir);
|
||||
res = simple_rmdir(parent, dir);
|
||||
/* We have to give up the mm_struct */
|
||||
spu_forget(SPUFS_I(d_inode(dir))->i_ctx);
|
||||
return res;
|
||||
struct spu_context *ctx = SPUFS_I(d_inode(dir))->i_ctx;
|
||||
|
||||
locked_recursive_removal(dir, NULL);
|
||||
spu_forget(ctx);
|
||||
}
|
||||
|
||||
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 dentry *dir;
|
||||
int ret;
|
||||
|
||||
dir = file->f_path.dentry;
|
||||
parent = d_inode(dir->d_parent);
|
||||
|
||||
inode_lock_nested(parent, I_MUTEX_PARENT);
|
||||
ret = spufs_rmdir(parent, dir);
|
||||
spufs_rmdir(parent, dir);
|
||||
inode_unlock(parent);
|
||||
WARN_ON(ret);
|
||||
|
||||
unuse_gang(dir->d_parent);
|
||||
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,
|
||||
mode, ctx);
|
||||
|
||||
inode_unlock(inode);
|
||||
|
||||
if (ret)
|
||||
spufs_rmdir(dir, dentry);
|
||||
|
||||
inode_unlock(inode);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -475,7 +444,7 @@ spufs_create_context(struct inode *inode, struct dentry *dentry,
|
|||
|
||||
ret = spufs_context_open(&path);
|
||||
if (ret < 0)
|
||||
WARN_ON(spufs_rmdir(inode, dentry));
|
||||
spufs_rmdir(inode, dentry);
|
||||
|
||||
out_aff_unlock:
|
||||
if (affinity)
|
||||
|
|
Loading…
Add table
Reference in a new issue