[PATCH] spufs: fix spufs_fill_dir error path
If creating one entry failed in spufs_fill_dir,
we never cleaned up the freshly created entries.
Fix this by calling the cleanup function on error.
Noticed by Al Viro.
Signed-off-by: Arnd Bergmann <arndb@de.ibm.com>
Signed-off-by: Paul Mackerras <paulus@samba.org>
diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c
index d9a39fb..687f80d 100644
--- a/arch/powerpc/platforms/cell/spufs/inode.c
+++ b/arch/powerpc/platforms/cell/spufs/inode.c
@@ -134,9 +134,48 @@
clear_inode(inode);
}
-static int
-spufs_fill_dir(struct dentry *dir, struct tree_descr *files,
- int mode, struct spu_context *ctx)
+static void spufs_prune_dir(struct dentry *dir)
+{
+ struct dentry *dentry, *tmp;
+ down(&dir->d_inode->i_sem);
+ list_for_each_entry_safe(dentry, tmp, &dir->d_subdirs, d_child) {
+ spin_lock(&dcache_lock);
+ spin_lock(&dentry->d_lock);
+ if (!(d_unhashed(dentry)) && dentry->d_inode) {
+ dget_locked(dentry);
+ __d_drop(dentry);
+ spin_unlock(&dentry->d_lock);
+ simple_unlink(dir->d_inode, dentry);
+ spin_unlock(&dcache_lock);
+ dput(dentry);
+ } else {
+ spin_unlock(&dentry->d_lock);
+ spin_unlock(&dcache_lock);
+ }
+ }
+ shrink_dcache_parent(dir);
+ up(&dir->d_inode->i_sem);
+}
+
+static int spufs_rmdir(struct inode *root, struct dentry *dir_dentry)
+{
+ struct spu_context *ctx;
+
+ /* remove all entries */
+ down(&root->i_sem);
+ spufs_prune_dir(dir_dentry);
+ up(&root->i_sem);
+
+ /* 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_sem here ? */
+ return simple_rmdir(root, dir_dentry);
+}
+
+static int spufs_fill_dir(struct dentry *dir, struct tree_descr *files,
+ int mode, struct spu_context *ctx)
{
struct dentry *dentry;
int ret;
@@ -154,46 +193,10 @@
}
return 0;
out:
- // FIXME: remove all files that are left
-
+ spufs_prune_dir(dir);
return ret;
}
-static int spufs_rmdir(struct inode *root, struct dentry *dir_dentry)
-{
- struct dentry *dentry, *tmp;
- struct spu_context *ctx;
-
- /* remove all entries */
- down(&root->i_sem);
- down(&dir_dentry->d_inode->i_sem);
- list_for_each_entry_safe(dentry, tmp, &dir_dentry->d_subdirs, d_child) {
- spin_lock(&dcache_lock);
- spin_lock(&dentry->d_lock);
- if (!(d_unhashed(dentry)) && dentry->d_inode) {
- dget_locked(dentry);
- __d_drop(dentry);
- spin_unlock(&dentry->d_lock);
- simple_unlink(dir_dentry->d_inode, dentry);
- spin_unlock(&dcache_lock);
- dput(dentry);
- } else {
- spin_unlock(&dentry->d_lock);
- spin_unlock(&dcache_lock);
- }
- }
- shrink_dcache_parent(dir_dentry);
- up(&dir_dentry->d_inode->i_sem);
- up(&root->i_sem);
-
- /* 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_sem here ? */
- return simple_rmdir(root, dir_dentry);
-}
-
static int spufs_dir_close(struct inode *inode, struct file *file)
{
struct inode *dir;