[PATCH 3/8] spufs: switch to locked_recursive_removal()

Al Viro
2025-06-14T06:02:32Z

... 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.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
arch/powerpc/platforms/cell/spufs/inode.c | 49 +++++------------------
1 file changed, 9 insertions(+), 40 deletions(-)

diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c
index 9f9e4b871627..7ec60290abe6 100644
--- a/arch/powerpc/platforms/cell/spufs/inode.c
+++ b/arch/powerpc/platforms/cell/spufs/inode.c
@@ -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)
--
2.39.5