aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/platforms/cell
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2013-01-28 20:37:21 -0500
committerAl Viro <viro@zeniv.linux.org.uk>2013-02-22 23:31:38 -0500
commit2248b87ec1d9f59001d8c69513b2892ac04a2a3d (patch)
tree1df3c5679e5fa10fdb7cc459f5c7108e7bee3b6c /arch/powerpc/platforms/cell
parent4e6b8973282829e0d5898d9721880556957f0f98 (diff)
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>
Diffstat (limited to 'arch/powerpc/platforms/cell')
-rw-r--r--arch/powerpc/platforms/cell/spufs/inode.c64
1 files changed, 21 insertions, 43 deletions
diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c
index 99db6161e5c9..863184b182f4 100644
--- a/arch/powerpc/platforms/cell/spufs/inode.c
+++ b/arch/powerpc/platforms/cell/spufs/inode.c
@@ -199,37 +199,18 @@ static int spufs_fill_dir(struct dentry *dir,
199 const struct spufs_tree_descr *files, umode_t mode, 199 const struct spufs_tree_descr *files, umode_t mode,
200 struct spu_context *ctx) 200 struct spu_context *ctx)
201{ 201{
202 struct dentry *dentry, *tmp;
203 int ret;
204
205 while (files->name && files->name[0]) { 202 while (files->name && files->name[0]) {
206 ret = -ENOMEM; 203 int ret;
207 dentry = d_alloc_name(dir, files->name); 204 struct dentry *dentry = d_alloc_name(dir, files->name);
208 if (!dentry) 205 if (!dentry)
209 goto out; 206 return -ENOMEM;
210 ret = spufs_new_file(dir->d_sb, dentry, files->ops, 207 ret = spufs_new_file(dir->d_sb, dentry, files->ops,
211 files->mode & mode, files->size, ctx); 208 files->mode & mode, files->size, ctx);
212 if (ret) 209 if (ret)
213 goto out; 210 return ret;
214 files++; 211 files++;
215 } 212 }
216 return 0; 213 return 0;
217out:
218 /*
219 * remove all children from dir. dir->inode is not set so don't
220 * just simply use spufs_prune_dir() and panic afterwards :)
221 * dput() looks like it will do the right thing:
222 * - dec parent's ref counter
223 * - remove child from parent's child list
224 * - free child's inode if possible
225 * - free child
226 */
227 list_for_each_entry_safe(dentry, tmp, &dir->d_subdirs, d_u.d_child) {
228 dput(dentry);
229 }
230
231 shrink_dcache_parent(dir);
232 return ret;
233} 214}
234 215
235static int spufs_dir_close(struct inode *inode, struct file *file) 216static 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,
269 struct inode *inode; 250 struct inode *inode;
270 struct spu_context *ctx; 251 struct spu_context *ctx;
271 252
272 ret = -ENOSPC;
273 inode = spufs_new_inode(dir->i_sb, mode | S_IFDIR); 253 inode = spufs_new_inode(dir->i_sb, mode | S_IFDIR);
274 if (!inode) 254 if (!inode)
275 goto out; 255 return -ENOSPC;
276 256
277 if (dir->i_mode & S_ISGID) { 257 if (dir->i_mode & S_ISGID) {
278 inode->i_gid = dir->i_gid; 258 inode->i_gid = dir->i_gid;
@@ -280,40 +260,38 @@ spufs_mkdir(struct inode *dir, struct dentry *dentry, unsigned int flags,
280 } 260 }
281 ctx = alloc_spu_context(SPUFS_I(dir)->i_gang); /* XXX gang */ 261 ctx = alloc_spu_context(SPUFS_I(dir)->i_gang); /* XXX gang */
282 SPUFS_I(inode)->i_ctx = ctx; 262 SPUFS_I(inode)->i_ctx = ctx;
283 if (!ctx) 263 if (!ctx) {
284 goto out_iput; 264 iput(inode);
265 return -ENOSPC;
266 }
285 267
286 ctx->flags = flags; 268 ctx->flags = flags;
287 inode->i_op = &simple_dir_inode_operations; 269 inode->i_op = &simple_dir_inode_operations;
288 inode->i_fop = &simple_dir_operations; 270 inode->i_fop = &simple_dir_operations;
271
272 mutex_lock(&inode->i_mutex);
273
274 dget(dentry);
275 inc_nlink(dir);
276 inc_nlink(inode);
277
278 d_instantiate(dentry, inode);
279
289 if (flags & SPU_CREATE_NOSCHED) 280 if (flags & SPU_CREATE_NOSCHED)
290 ret = spufs_fill_dir(dentry, spufs_dir_nosched_contents, 281 ret = spufs_fill_dir(dentry, spufs_dir_nosched_contents,
291 mode, ctx); 282 mode, ctx);
292 else 283 else
293 ret = spufs_fill_dir(dentry, spufs_dir_contents, mode, ctx); 284 ret = spufs_fill_dir(dentry, spufs_dir_contents, mode, ctx);
294 285
295 if (ret) 286 if (!ret && spufs_get_sb_info(dir->i_sb)->debug)
296 goto out_free_ctx;
297
298 if (spufs_get_sb_info(dir->i_sb)->debug)
299 ret = spufs_fill_dir(dentry, spufs_dir_debug_contents, 287 ret = spufs_fill_dir(dentry, spufs_dir_debug_contents,
300 mode, ctx); 288 mode, ctx);
301 289
302 if (ret) 290 if (ret)
303 goto out_free_ctx; 291 spufs_rmdir(dir, dentry);
304 292
305 d_instantiate(dentry, inode); 293 mutex_unlock(&inode->i_mutex);
306 dget(dentry);
307 inc_nlink(dir);
308 inc_nlink(dentry->d_inode);
309 goto out;
310 294
311out_free_ctx:
312 spu_forget(ctx);
313 put_spu_context(ctx);
314out_iput:
315 iput(inode);
316out:
317 return ret; 295 return ret;
318} 296}
319 297