summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastian Siewior <bigeasy@linux.vnet.ibm.com>2007-06-06 14:03:58 +1000
committerPaul Mackerras <paulus@samba.org>2007-06-07 11:44:40 +1000
commit87873c86802ba7ff9d9550d06459a6e99d72c5eb (patch)
treec077539fbf5eca8010d4edfa8fd5771a4926101c
parent5e1e9ba690a2e2135a8f997242f9c46d2b8ac033 (diff)
[POWERPC] spufs: Fix error handling in spufs_fill_dir()
The error path in spufs_fill_dir() is broken. If d_alloc_name() or spufs_new_file() fails, spufs_prune_dir() is getting called. At this time dir->inode is not set and a NULL pointer is dereferenced by mutex_lock(). This bugfix replaces spufs_prune_dir() with a shorter version that does not touch dir->inode but simply removes all children. Signed-off-by: Sebastian Siewior <bigeasy@linux.vnet.ibm.com> Signed-off-by: Jeremy Kerr <jk@ozlabs.org> Acked-by: Arnd Bergmann <arnd.bergmann@de.ibm.com> Signed-off-by: Paul Mackerras <paulus@samba.org>
-rw-r--r--arch/powerpc/platforms/cell/spufs/inode.c17
1 files changed, 15 insertions, 2 deletions
diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c
index 08356813977..9807206e021 100644
--- a/arch/powerpc/platforms/cell/spufs/inode.c
+++ b/arch/powerpc/platforms/cell/spufs/inode.c
@@ -177,7 +177,7 @@ static int spufs_rmdir(struct inode *parent, struct dentry *dir)
static int spufs_fill_dir(struct dentry *dir, struct tree_descr *files,
int mode, struct spu_context *ctx)
{
- struct dentry *dentry;
+ struct dentry *dentry, *tmp;
int ret;
while (files->name && files->name[0]) {
@@ -193,7 +193,20 @@ static int spufs_fill_dir(struct dentry *dir, struct tree_descr *files,
}
return 0;
out:
- spufs_prune_dir(dir);
+ /*
+ * remove all children from dir. dir->inode is not set so don't
+ * just simply use spufs_prune_dir() and panic afterwards :)
+ * dput() looks like it will do the right thing:
+ * - dec parent's ref counter
+ * - remove child from parent's child list
+ * - free child's inode if possible
+ * - free child
+ */
+ list_for_each_entry_safe(dentry, tmp, &dir->d_subdirs, d_u.d_child) {
+ dput(dentry);
+ }
+
+ shrink_dcache_parent(dir);
return ret;
}