]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
spufs: switch to locked_recursive_removal()
authorAl Viro <viro@zeniv.linux.org.uk>
Thu, 9 May 2024 20:36:24 +0000 (16:36 -0400)
committerAl Viro <viro@zeniv.linux.org.uk>
Thu, 3 Jul 2025 02:36:51 +0000 (22:36 -0400)
... 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>
arch/powerpc/platforms/cell/spufs/inode.c

index 9f9e4b871627826223d42eca55d1cd55e9cb9b30..7ec60290abe640b30457915773d776b38e88c827 100644 (file)
@@ -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)