diff options
author | Arnd Bergmann <arnd@arndb.de> | 2006-01-04 14:31:26 -0500 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2006-01-08 23:44:41 -0500 |
commit | 346f4d3ce948a381a559dcaefb141d79f492335c (patch) | |
tree | 47028cc77555850a235574b01e9a2eb398361074 /arch/powerpc | |
parent | 0106246594a05f02a6be6ee4695c7584c758fa7f (diff) |
[PATCH] spufs: dont leak directories in failed spu_create
If get_unused_fd failed in sys_spu_create, we never cleaned
up the created directory. Fix that by restructuring the
error path.
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')
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/inode.c | 54 |
1 files changed, 37 insertions, 17 deletions
diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c index e314f18eccdd..d9a39fb63a8a 100644 --- a/arch/powerpc/platforms/cell/spufs/inode.c +++ b/arch/powerpc/platforms/cell/spufs/inode.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/init.h> | 26 | #include <linux/init.h> |
27 | #include <linux/ioctl.h> | 27 | #include <linux/ioctl.h> |
28 | #include <linux/module.h> | 28 | #include <linux/module.h> |
29 | #include <linux/mount.h> | ||
29 | #include <linux/namei.h> | 30 | #include <linux/namei.h> |
30 | #include <linux/pagemap.h> | 31 | #include <linux/pagemap.h> |
31 | #include <linux/poll.h> | 32 | #include <linux/poll.h> |
@@ -251,6 +252,7 @@ spufs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
251 | d_instantiate(dentry, inode); | 252 | d_instantiate(dentry, inode); |
252 | dget(dentry); | 253 | dget(dentry); |
253 | dir->i_nlink++; | 254 | dir->i_nlink++; |
255 | dentry->d_inode->i_nlink++; | ||
254 | goto out; | 256 | goto out; |
255 | 257 | ||
256 | out_free_ctx: | 258 | out_free_ctx: |
@@ -261,18 +263,44 @@ out: | |||
261 | return ret; | 263 | return ret; |
262 | } | 264 | } |
263 | 265 | ||
266 | static int spufs_context_open(struct dentry *dentry, struct vfsmount *mnt) | ||
267 | { | ||
268 | int ret; | ||
269 | struct file *filp; | ||
270 | |||
271 | ret = get_unused_fd(); | ||
272 | if (ret < 0) { | ||
273 | dput(dentry); | ||
274 | mntput(mnt); | ||
275 | goto out; | ||
276 | } | ||
277 | |||
278 | filp = dentry_open(dentry, mnt, O_RDONLY); | ||
279 | if (IS_ERR(filp)) { | ||
280 | put_unused_fd(ret); | ||
281 | ret = PTR_ERR(filp); | ||
282 | goto out; | ||
283 | } | ||
284 | |||
285 | filp->f_op = &spufs_context_fops; | ||
286 | fd_install(ret, filp); | ||
287 | out: | ||
288 | return ret; | ||
289 | } | ||
290 | |||
291 | static struct file_system_type spufs_type; | ||
292 | |||
264 | long | 293 | long |
265 | spufs_create_thread(struct nameidata *nd, const char *name, | 294 | spufs_create_thread(struct nameidata *nd, const char *name, |
266 | unsigned int flags, mode_t mode) | 295 | unsigned int flags, mode_t mode) |
267 | { | 296 | { |
268 | struct dentry *dentry; | 297 | struct dentry *dentry; |
269 | struct file *filp; | ||
270 | int ret; | 298 | int ret; |
271 | 299 | ||
272 | /* need to be at the root of spufs */ | 300 | /* need to be at the root of spufs */ |
273 | ret = -EINVAL; | 301 | ret = -EINVAL; |
274 | if (nd->dentry->d_sb->s_magic != SPUFS_MAGIC || | 302 | if (nd->dentry->d_sb->s_type != &spufs_type || |
275 | nd->dentry != nd->dentry->d_sb->s_root) | 303 | nd->dentry != nd->dentry->d_sb->s_root) |
276 | goto out; | 304 | goto out; |
277 | 305 | ||
278 | dentry = lookup_create(nd, 1); | 306 | dentry = lookup_create(nd, 1); |
@@ -289,21 +317,13 @@ spufs_create_thread(struct nameidata *nd, const char *name, | |||
289 | if (ret) | 317 | if (ret) |
290 | goto out_dput; | 318 | goto out_dput; |
291 | 319 | ||
292 | ret = get_unused_fd(); | 320 | /* |
321 | * get references for dget and mntget, will be released | ||
322 | * in error path of *_open(). | ||
323 | */ | ||
324 | ret = spufs_context_open(dget(dentry), mntget(nd->mnt)); | ||
293 | if (ret < 0) | 325 | if (ret < 0) |
294 | goto out_dput; | 326 | spufs_rmdir(nd->dentry->d_inode, dentry); |
295 | |||
296 | dentry->d_inode->i_nlink++; | ||
297 | |||
298 | filp = filp_open(name, O_RDONLY, mode); | ||
299 | if (IS_ERR(filp)) { | ||
300 | // FIXME: remove directory again | ||
301 | put_unused_fd(ret); | ||
302 | ret = PTR_ERR(filp); | ||
303 | } else { | ||
304 | filp->f_op = &spufs_context_fops; | ||
305 | fd_install(ret, filp); | ||
306 | } | ||
307 | 327 | ||
308 | out_dput: | 328 | out_dput: |
309 | dput(dentry); | 329 | dput(dentry); |