diff options
author | Arnd Bergmann <arnd@arndb.de> | 2006-01-04 20:31:27 +0100 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2006-01-09 15:44:42 +1100 |
commit | 3f51dd91c80746a5cf76f8c4a77bfc88aa82bb9e (patch) | |
tree | f92d9867e51a10b73a3f48fa3d65413f186ac733 /arch/powerpc/platforms/cell | |
parent | 346f4d3ce948a381a559dcaefb141d79f492335c (diff) |
[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>
Diffstat (limited to 'arch/powerpc/platforms/cell')
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/inode.c | 73 |
1 files changed, 38 insertions, 35 deletions
diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c index d9a39fb63a8..687f80d09f4 100644 --- a/arch/powerpc/platforms/cell/spufs/inode.c +++ b/arch/powerpc/platforms/cell/spufs/inode.c @@ -134,47 +134,18 @@ spufs_delete_inode(struct inode *inode) clear_inode(inode); } -static int -spufs_fill_dir(struct dentry *dir, struct tree_descr *files, - int mode, struct spu_context *ctx) -{ - struct dentry *dentry; - int ret; - - while (files->name && files->name[0]) { - ret = -ENOMEM; - dentry = d_alloc_name(dir, files->name); - if (!dentry) - goto out; - ret = spufs_new_file(dir->d_sb, dentry, files->ops, - files->mode & mode, ctx); - if (ret) - goto out; - files++; - } - return 0; -out: - // FIXME: remove all files that are left - - return ret; -} - -static int spufs_rmdir(struct inode *root, struct dentry *dir_dentry) +static void spufs_prune_dir(struct dentry *dir) { 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) { + 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_dentry->d_inode, dentry); + simple_unlink(dir->d_inode, dentry); spin_unlock(&dcache_lock); dput(dentry); } else { @@ -182,8 +153,17 @@ static int spufs_rmdir(struct inode *root, struct dentry *dir_dentry) spin_unlock(&dcache_lock); } } - shrink_dcache_parent(dir_dentry); - up(&dir_dentry->d_inode->i_sem); + 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 */ @@ -194,6 +174,29 @@ static int spufs_rmdir(struct inode *root, struct dentry *dir_dentry) 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; + + while (files->name && files->name[0]) { + ret = -ENOMEM; + dentry = d_alloc_name(dir, files->name); + if (!dentry) + goto out; + ret = spufs_new_file(dir->d_sb, dentry, files->ops, + files->mode & mode, ctx); + if (ret) + goto out; + files++; + } + return 0; +out: + spufs_prune_dir(dir); + return ret; +} + static int spufs_dir_close(struct inode *inode, struct file *file) { struct inode *dir; |