mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-30 08:02:30 +00:00
[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>
This commit is contained in:
parent
346f4d3ce9
commit
3f51dd91c8
1 changed files with 43 additions and 40 deletions
|
@ -134,9 +134,48 @@ 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)
|
||||
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 @@ spufs_fill_dir(struct dentry *dir, struct tree_descr *files,
|
|||
}
|
||||
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;
|
||||
|
|
Loading…
Reference in a new issue