]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - fs/ext4/namei.c
Merge branch 'ras-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[linux.git] / fs / ext4 / namei.c
index a427d2031a8dacb1f4a0379da72c85d3bfbd746a..a856997d87b54c83ae59ea78ed9475a8e4a3c855 100644 (file)
@@ -2547,18 +2547,29 @@ static void ext4_dec_count(handle_t *handle, struct inode *inode)
 }
 
 
+/*
+ * Add non-directory inode to a directory. On success, the inode reference is
+ * consumed by dentry is instantiation. This is also indicated by clearing of
+ * *inodep pointer. On failure, the caller is responsible for dropping the
+ * inode reference in the safe context.
+ */
 static int ext4_add_nondir(handle_t *handle,
-               struct dentry *dentry, struct inode *inode)
+               struct dentry *dentry, struct inode **inodep)
 {
+       struct inode *dir = d_inode(dentry->d_parent);
+       struct inode *inode = *inodep;
        int err = ext4_add_entry(handle, dentry, inode);
        if (!err) {
                ext4_mark_inode_dirty(handle, inode);
+               if (IS_DIRSYNC(dir))
+                       ext4_handle_sync(handle);
                d_instantiate_new(dentry, inode);
+               *inodep = NULL;
                return 0;
        }
        drop_nlink(inode);
+       ext4_orphan_add(handle, inode);
        unlock_new_inode(inode);
-       iput(inode);
        return err;
 }
 
@@ -2592,12 +2603,12 @@ static int ext4_create(struct inode *dir, struct dentry *dentry, umode_t mode,
                inode->i_op = &ext4_file_inode_operations;
                inode->i_fop = &ext4_file_operations;
                ext4_set_aops(inode);
-               err = ext4_add_nondir(handle, dentry, inode);
-               if (!err && IS_DIRSYNC(dir))
-                       ext4_handle_sync(handle);
+               err = ext4_add_nondir(handle, dentry, &inode);
        }
        if (handle)
                ext4_journal_stop(handle);
+       if (!IS_ERR_OR_NULL(inode))
+               iput(inode);
        if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries))
                goto retry;
        return err;
@@ -2624,12 +2635,12 @@ static int ext4_mknod(struct inode *dir, struct dentry *dentry,
        if (!IS_ERR(inode)) {
                init_special_inode(inode, inode->i_mode, rdev);
                inode->i_op = &ext4_special_inode_operations;
-               err = ext4_add_nondir(handle, dentry, inode);
-               if (!err && IS_DIRSYNC(dir))
-                       ext4_handle_sync(handle);
+               err = ext4_add_nondir(handle, dentry, &inode);
        }
        if (handle)
                ext4_journal_stop(handle);
+       if (!IS_ERR_OR_NULL(inode))
+               iput(inode);
        if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries))
                goto retry;
        return err;
@@ -2779,10 +2790,12 @@ static int ext4_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
        if (err) {
 out_clear_inode:
                clear_nlink(inode);
+               ext4_orphan_add(handle, inode);
                unlock_new_inode(inode);
                ext4_mark_inode_dirty(handle, inode);
+               ext4_journal_stop(handle);
                iput(inode);
-               goto out_stop;
+               goto out_retry;
        }
        ext4_inc_count(handle, dir);
        ext4_update_dx_flag(dir);
@@ -2796,6 +2809,7 @@ static int ext4_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
 out_stop:
        if (handle)
                ext4_journal_stop(handle);
+out_retry:
        if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries))
                goto retry;
        return err;
@@ -3182,18 +3196,17 @@ static int ext4_unlink(struct inode *dir, struct dentry *dentry)
        if (IS_DIRSYNC(dir))
                ext4_handle_sync(handle);
 
-       if (inode->i_nlink == 0) {
-               ext4_warning_inode(inode, "Deleting file '%.*s' with no links",
-                                  dentry->d_name.len, dentry->d_name.name);
-               set_nlink(inode, 1);
-       }
        retval = ext4_delete_entry(handle, dir, de, bh);
        if (retval)
                goto end_unlink;
        dir->i_ctime = dir->i_mtime = current_time(dir);
        ext4_update_dx_flag(dir);
        ext4_mark_inode_dirty(handle, dir);
-       drop_nlink(inode);
+       if (inode->i_nlink == 0)
+               ext4_warning_inode(inode, "Deleting file '%.*s' with no links",
+                                  dentry->d_name.len, dentry->d_name.name);
+       else
+               drop_nlink(inode);
        if (!inode->i_nlink)
                ext4_orphan_add(handle, inode);
        inode->i_ctime = current_time(inode);
@@ -3328,12 +3341,11 @@ static int ext4_symlink(struct inode *dir,
                inode->i_size = disk_link.len - 1;
        }
        EXT4_I(inode)->i_disksize = inode->i_size;
-       err = ext4_add_nondir(handle, dentry, inode);
-       if (!err && IS_DIRSYNC(dir))
-               ext4_handle_sync(handle);
-
+       err = ext4_add_nondir(handle, dentry, &inode);
        if (handle)
                ext4_journal_stop(handle);
+       if (inode)
+               iput(inode);
        goto out_free_encrypted_link;
 
 err_drop_inode: