Browse Source

spufs_mkdir(): don't d_add() on negative parent

NOTE: this really needs testing - I could've easily fucked up
refcounting in there.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Al Viro 12 years ago
parent
commit
2248b87ec1
1 changed files with 21 additions and 43 deletions
  1. 21 43
      arch/powerpc/platforms/cell/spufs/inode.c

+ 21 - 43
arch/powerpc/platforms/cell/spufs/inode.c

@@ -199,37 +199,18 @@ static int spufs_fill_dir(struct dentry *dir,
 		const struct spufs_tree_descr *files, umode_t mode,
 		struct spu_context *ctx)
 {
-	struct dentry *dentry, *tmp;
-	int ret;
-
 	while (files->name && files->name[0]) {
-		ret = -ENOMEM;
-		dentry = d_alloc_name(dir, files->name);
+		int ret;
+		struct dentry *dentry = d_alloc_name(dir, files->name);
 		if (!dentry)
-			goto out;
+			return -ENOMEM;
 		ret = spufs_new_file(dir->d_sb, dentry, files->ops,
 					files->mode & mode, files->size, ctx);
 		if (ret)
-			goto out;
+			return ret;
 		files++;
 	}
 	return 0;
-out:
-	/*
-	 * 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;
 }
 
 static int spufs_dir_close(struct inode *inode, struct file *file)
@@ -269,10 +250,9 @@ spufs_mkdir(struct inode *dir, struct dentry *dentry, unsigned int flags,
 	struct inode *inode;
 	struct spu_context *ctx;
 
-	ret = -ENOSPC;
 	inode = spufs_new_inode(dir->i_sb, mode | S_IFDIR);
 	if (!inode)
-		goto out;
+		return -ENOSPC;
 
 	if (dir->i_mode & S_ISGID) {
 		inode->i_gid = dir->i_gid;
@@ -280,40 +260,38 @@ spufs_mkdir(struct inode *dir, struct dentry *dentry, unsigned int flags,
 	}
 	ctx = alloc_spu_context(SPUFS_I(dir)->i_gang); /* XXX gang */
 	SPUFS_I(inode)->i_ctx = ctx;
-	if (!ctx)
-		goto out_iput;
+	if (!ctx) {
+		iput(inode);
+		return -ENOSPC;
+	}
 
 	ctx->flags = flags;
 	inode->i_op = &simple_dir_inode_operations;
 	inode->i_fop = &simple_dir_operations;
+
+	mutex_lock(&inode->i_mutex);
+
+	dget(dentry);
+	inc_nlink(dir);
+	inc_nlink(inode);
+
+	d_instantiate(dentry, inode);
+
 	if (flags & SPU_CREATE_NOSCHED)
 		ret = spufs_fill_dir(dentry, spufs_dir_nosched_contents,
 					 mode, ctx);
 	else
 		ret = spufs_fill_dir(dentry, spufs_dir_contents, mode, ctx);
 
-	if (ret)
-		goto out_free_ctx;
-
-	if (spufs_get_sb_info(dir->i_sb)->debug)
+	if (!ret && spufs_get_sb_info(dir->i_sb)->debug)
 		ret = spufs_fill_dir(dentry, spufs_dir_debug_contents,
 				mode, ctx);
 
 	if (ret)
-		goto out_free_ctx;
+		spufs_rmdir(dir, dentry);
 
-	d_instantiate(dentry, inode);
-	dget(dentry);
-	inc_nlink(dir);
-	inc_nlink(dentry->d_inode);
-	goto out;
+	mutex_unlock(&inode->i_mutex);
 
-out_free_ctx:
-	spu_forget(ctx);
-	put_spu_context(ctx);
-out_iput:
-	iput(inode);
-out:
 	return ret;
 }