diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2011-03-04 01:31:03 -0500 |
---|---|---|
committer | Bob Copeland <me@bobcopeland.com> | 2011-03-05 16:24:01 -0500 |
commit | d932805b3dc8c6d80d8948f7d7d0d8336d53b2ed (patch) | |
tree | 5024d697f1b3b6c8fcfe627718ece4020102df1b | |
parent | cdb26496dba00d5c4375261be6518b3e94260444 (diff) |
omfs: merge unlink() and rmdir(), close leak in rename()
In case of directory-overwriting rename(), omfs forgot to mark the
victim doomed, so omfs_evict_inode() didn't free it.
We could fix that by calling omfs_rmdir() for directory victims
instead of doing omfs_unlink(), but it's easier to merge omfs_unlink()
and omfs_rmdir() instead. Note that we have no hardlinks here.
It also makes the checks in omfs_rename() go away - they fold into
what omfs_remove() does when it runs into a directory.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Bob Copeland <me@bobcopeland.com>
-rw-r--r-- | fs/omfs/dir.c | 53 |
1 files changed, 13 insertions, 40 deletions
diff --git a/fs/omfs/dir.c b/fs/omfs/dir.c index a4c2d31b785e..fd91f629ceb8 100644 --- a/fs/omfs/dir.c +++ b/fs/omfs/dir.c | |||
@@ -235,33 +235,22 @@ static int omfs_dir_is_empty(struct inode *inode) | |||
235 | return *ptr != ~0; | 235 | return *ptr != ~0; |
236 | } | 236 | } |
237 | 237 | ||
238 | static int omfs_unlink(struct inode *dir, struct dentry *dentry) | 238 | static int omfs_remove(struct inode *dir, struct dentry *dentry) |
239 | { | 239 | { |
240 | int ret; | ||
241 | struct inode *inode = dentry->d_inode; | 240 | struct inode *inode = dentry->d_inode; |
241 | int ret; | ||
242 | |||
243 | if (S_ISDIR(inode->i_mode) && !omfs_dir_is_empty(inode)) | ||
244 | return -ENOTEMPTY; | ||
242 | 245 | ||
243 | ret = omfs_delete_entry(dentry); | 246 | ret = omfs_delete_entry(dentry); |
244 | if (ret) | 247 | if (ret) |
245 | goto end_unlink; | 248 | return ret; |
246 | 249 | ||
247 | inode_dec_link_count(inode); | 250 | clear_nlink(inode); |
251 | mark_inode_dirty(inode); | ||
248 | mark_inode_dirty(dir); | 252 | mark_inode_dirty(dir); |
249 | 253 | return 0; | |
250 | end_unlink: | ||
251 | return ret; | ||
252 | } | ||
253 | |||
254 | static int omfs_rmdir(struct inode *dir, struct dentry *dentry) | ||
255 | { | ||
256 | int err = -ENOTEMPTY; | ||
257 | struct inode *inode = dentry->d_inode; | ||
258 | |||
259 | if (omfs_dir_is_empty(inode)) { | ||
260 | err = omfs_unlink(dir, dentry); | ||
261 | if (!err) | ||
262 | inode_dec_link_count(inode); | ||
263 | } | ||
264 | return err; | ||
265 | } | 254 | } |
266 | 255 | ||
267 | static int omfs_add_node(struct inode *dir, struct dentry *dentry, int mode) | 256 | static int omfs_add_node(struct inode *dir, struct dentry *dentry, int mode) |
@@ -385,33 +374,17 @@ static int omfs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
385 | { | 374 | { |
386 | struct inode *new_inode = new_dentry->d_inode; | 375 | struct inode *new_inode = new_dentry->d_inode; |
387 | struct inode *old_inode = old_dentry->d_inode; | 376 | struct inode *old_inode = old_dentry->d_inode; |
388 | struct buffer_head *bh; | ||
389 | int is_dir; | ||
390 | int err; | 377 | int err; |
391 | 378 | ||
392 | is_dir = S_ISDIR(old_inode->i_mode); | ||
393 | |||
394 | if (new_inode) { | 379 | if (new_inode) { |
395 | /* overwriting existing file/dir */ | 380 | /* overwriting existing file/dir */ |
396 | err = -ENOTEMPTY; | 381 | err = omfs_remove(new_dir, new_dentry); |
397 | if (is_dir && !omfs_dir_is_empty(new_inode)) | ||
398 | goto out; | ||
399 | |||
400 | err = -ENOENT; | ||
401 | bh = omfs_find_entry(new_dir, new_dentry->d_name.name, | ||
402 | new_dentry->d_name.len); | ||
403 | if (IS_ERR(bh)) | ||
404 | goto out; | ||
405 | brelse(bh); | ||
406 | |||
407 | err = omfs_unlink(new_dir, new_dentry); | ||
408 | if (err) | 382 | if (err) |
409 | goto out; | 383 | goto out; |
410 | } | 384 | } |
411 | 385 | ||
412 | /* since omfs locates files by name, we need to unlink _before_ | 386 | /* since omfs locates files by name, we need to unlink _before_ |
413 | * adding the new link or we won't find the old one */ | 387 | * adding the new link or we won't find the old one */ |
414 | inode_inc_link_count(old_inode); | ||
415 | err = omfs_delete_entry(old_dentry); | 388 | err = omfs_delete_entry(old_dentry); |
416 | if (err) | 389 | if (err) |
417 | goto out; | 390 | goto out; |
@@ -488,8 +461,8 @@ const struct inode_operations omfs_dir_inops = { | |||
488 | .mkdir = omfs_mkdir, | 461 | .mkdir = omfs_mkdir, |
489 | .rename = omfs_rename, | 462 | .rename = omfs_rename, |
490 | .create = omfs_create, | 463 | .create = omfs_create, |
491 | .unlink = omfs_unlink, | 464 | .unlink = omfs_remove, |
492 | .rmdir = omfs_rmdir, | 465 | .rmdir = omfs_remove, |
493 | }; | 466 | }; |
494 | 467 | ||
495 | const struct file_operations omfs_dir_operations = { | 468 | const struct file_operations omfs_dir_operations = { |