omfs: merge unlink() and rmdir(), close leak in rename()
Al Viro [Fri, 4 Mar 2011 06:31:03 +0000 (01:31 -0500)]
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>

fs/omfs/dir.c

index a4c2d31..fd91f62 100644 (file)
@@ -235,33 +235,22 @@ static int omfs_dir_is_empty(struct inode *inode)
        return *ptr != ~0;
 }
 
-static int omfs_unlink(struct inode *dir, struct dentry *dentry)
+static int omfs_remove(struct inode *dir, struct dentry *dentry)
 {
-       int ret;
        struct inode *inode = dentry->d_inode;
+       int ret;
+
+       if (S_ISDIR(inode->i_mode) && !omfs_dir_is_empty(inode))
+               return -ENOTEMPTY;
 
        ret = omfs_delete_entry(dentry);
        if (ret)
-               goto end_unlink;
-
-       inode_dec_link_count(inode);
+               return ret;
+       
+       clear_nlink(inode);
+       mark_inode_dirty(inode);
        mark_inode_dirty(dir);
-
-end_unlink:
-       return ret;
-}
-
-static int omfs_rmdir(struct inode *dir, struct dentry *dentry)
-{
-       int err = -ENOTEMPTY;
-       struct inode *inode = dentry->d_inode;
-
-       if (omfs_dir_is_empty(inode)) {
-               err = omfs_unlink(dir, dentry);
-               if (!err)
-                       inode_dec_link_count(inode);
-       }
-       return err;
+       return 0;
 }
 
 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,
 {
        struct inode *new_inode = new_dentry->d_inode;
        struct inode *old_inode = old_dentry->d_inode;
-       struct buffer_head *bh;
-       int is_dir;
        int err;
 
-       is_dir = S_ISDIR(old_inode->i_mode);
-
        if (new_inode) {
                /* overwriting existing file/dir */
-               err = -ENOTEMPTY;
-               if (is_dir && !omfs_dir_is_empty(new_inode))
-                       goto out;
-
-               err = -ENOENT;
-               bh = omfs_find_entry(new_dir, new_dentry->d_name.name,
-                       new_dentry->d_name.len);
-               if (IS_ERR(bh))
-                       goto out;
-               brelse(bh);
-
-               err = omfs_unlink(new_dir, new_dentry);
+               err = omfs_remove(new_dir, new_dentry);
                if (err)
                        goto out;
        }
 
        /* since omfs locates files by name, we need to unlink _before_
         * adding the new link or we won't find the old one */
-       inode_inc_link_count(old_inode);
        err = omfs_delete_entry(old_dentry);
        if (err)
                goto out;
@@ -488,8 +461,8 @@ const struct inode_operations omfs_dir_inops = {
        .mkdir = omfs_mkdir,
        .rename = omfs_rename,
        .create = omfs_create,
-       .unlink = omfs_unlink,
-       .rmdir = omfs_rmdir,
+       .unlink = omfs_remove,
+       .rmdir = omfs_remove,
 };
 
 const struct file_operations omfs_dir_operations = {