ext4: avoid unnecessary stalls in ext4_evict_inode()
[sfrench/cifs-2.6.git] / fs / ext4 / inode.c
index 986efd9511ac5ed1fc6b85ecf591397411288551..754c2190af3148cd60f1d0a8006918ef3198937a 100644 (file)
@@ -139,6 +139,8 @@ static void ext4_invalidatepage(struct page *page, unsigned int offset,
                                unsigned int length);
 static int __ext4_journalled_writepage(struct page *page, unsigned int len);
 static int ext4_bh_delay_or_unwritten(handle_t *handle, struct buffer_head *bh);
+static int ext4_meta_trans_blocks(struct inode *inode, int lblocks,
+                                 int pextents);
 
 /*
  * Test whether an inode is a fast symlink.
@@ -188,7 +190,7 @@ void ext4_evict_inode(struct inode *inode)
        handle_t *handle;
        int err;
        int extra_credits = 3;
-       struct ext4_xattr_ino_array *lea_ino_array = NULL;
+       struct ext4_xattr_inode_array *ea_inode_array = NULL;
 
        trace_ext4_evict_inode(inode);
 
@@ -213,7 +215,8 @@ void ext4_evict_inode(struct inode *inode)
                 */
                if (inode->i_ino != EXT4_JOURNAL_INO &&
                    ext4_should_journal_data(inode) &&
-                   (S_ISLNK(inode->i_mode) || S_ISREG(inode->i_mode))) {
+                   (S_ISLNK(inode->i_mode) || S_ISREG(inode->i_mode)) &&
+                   inode->i_data.nrpages) {
                        journal_t *journal = EXT4_SB(inode->i_sb)->s_journal;
                        tid_t commit_tid = EXT4_I(inode)->i_datasync_tid;
 
@@ -239,7 +242,11 @@ void ext4_evict_inode(struct inode *inode)
         */
        sb_start_intwrite(inode->i_sb);
 
-       handle = ext4_journal_start(inode, EXT4_HT_TRUNCATE, extra_credits);
+       if (!IS_NOQUOTA(inode))
+               extra_credits += EXT4_MAXQUOTAS_DEL_BLOCKS(inode->i_sb);
+
+       handle = ext4_journal_start(inode, EXT4_HT_TRUNCATE,
+                                ext4_blocks_for_truncate(inode)+extra_credits);
        if (IS_ERR(handle)) {
                ext4_std_error(inode->i_sb, PTR_ERR(handle));
                /*
@@ -251,36 +258,9 @@ void ext4_evict_inode(struct inode *inode)
                sb_end_intwrite(inode->i_sb);
                goto no_delete;
        }
+
        if (IS_SYNC(inode))
                ext4_handle_sync(handle);
-
-       /*
-        * Delete xattr inode before deleting the main inode.
-        */
-       err = ext4_xattr_delete_inode(handle, inode, &lea_ino_array);
-       if (err) {
-               ext4_warning(inode->i_sb,
-                            "couldn't delete inode's xattr (err %d)", err);
-               goto stop_handle;
-       }
-
-       if (!IS_NOQUOTA(inode))
-               extra_credits += 2 * EXT4_QUOTA_DEL_BLOCKS(inode->i_sb);
-
-       if (!ext4_handle_has_enough_credits(handle,
-                       ext4_blocks_for_truncate(inode) + extra_credits)) {
-               err = ext4_journal_extend(handle,
-                       ext4_blocks_for_truncate(inode) + extra_credits);
-               if (err > 0)
-                       err = ext4_journal_restart(handle,
-                       ext4_blocks_for_truncate(inode) + extra_credits);
-               if (err != 0) {
-                       ext4_warning(inode->i_sb,
-                                    "couldn't extend journal (err %d)", err);
-                       goto stop_handle;
-               }
-       }
-
        inode->i_size = 0;
        err = ext4_mark_inode_dirty(handle, inode);
        if (err) {
@@ -298,25 +278,17 @@ void ext4_evict_inode(struct inode *inode)
                }
        }
 
-       /*
-        * ext4_ext_truncate() doesn't reserve any slop when it
-        * restarts journal transactions; therefore there may not be
-        * enough credits left in the handle to remove the inode from
-        * the orphan list and set the dtime field.
-        */
-       if (!ext4_handle_has_enough_credits(handle, extra_credits)) {
-               err = ext4_journal_extend(handle, extra_credits);
-               if (err > 0)
-                       err = ext4_journal_restart(handle, extra_credits);
-               if (err != 0) {
-                       ext4_warning(inode->i_sb,
-                                    "couldn't extend journal (err %d)", err);
-               stop_handle:
-                       ext4_journal_stop(handle);
-                       ext4_orphan_del(NULL, inode);
-                       sb_end_intwrite(inode->i_sb);
-                       goto no_delete;
-               }
+       /* Remove xattr references. */
+       err = ext4_xattr_delete_inode(handle, inode, &ea_inode_array,
+                                     extra_credits);
+       if (err) {
+               ext4_warning(inode->i_sb, "xattr delete (err %d)", err);
+stop_handle:
+               ext4_journal_stop(handle);
+               ext4_orphan_del(NULL, inode);
+               sb_end_intwrite(inode->i_sb);
+               ext4_xattr_inode_array_free(ea_inode_array);
+               goto no_delete;
        }
 
        /*
@@ -342,12 +314,9 @@ void ext4_evict_inode(struct inode *inode)
                ext4_clear_inode(inode);
        else
                ext4_free_inode(handle, inode);
-
        ext4_journal_stop(handle);
        sb_end_intwrite(inode->i_sb);
-
-       if (lea_ino_array != NULL)
-               ext4_xattr_inode_array_free(inode, lea_ino_array);
+       ext4_xattr_inode_array_free(ea_inode_array);
        return;
 no_delete:
        ext4_clear_inode(inode);        /* We must guarantee clearing of inode... */
@@ -741,7 +710,7 @@ out_sem:
                if (map->m_flags & EXT4_MAP_NEW &&
                    !(map->m_flags & EXT4_MAP_UNWRITTEN) &&
                    !(flags & EXT4_GET_BLOCKS_ZERO) &&
-                   !IS_NOQUOTA(inode) &&
+                   !ext4_is_quota_file(inode) &&
                    ext4_should_order_data(inode)) {
                        if (flags & EXT4_GET_BLOCKS_IO_SUBMIT)
                                ret = ext4_jbd2_inode_add_wait(handle, inode);
@@ -4877,6 +4846,15 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
        }
        brelse(iloc.bh);
        ext4_set_inode_flags(inode);
+
+       if (ei->i_flags & EXT4_EA_INODE_FL) {
+               ext4_xattr_inode_set_class(inode);
+
+               inode_lock(inode);
+               inode->i_flags |= S_NOQUOTA;
+               inode_unlock(inode);
+       }
+
        unlock_new_inode(inode);
        return inode;
 
@@ -5318,7 +5296,14 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr)
                        error = PTR_ERR(handle);
                        goto err_out;
                }
+
+               /* dquot_transfer() calls back ext4_get_inode_usage() which
+                * counts xattr inode references.
+                */
+               down_read(&EXT4_I(inode)->xattr_sem);
                error = dquot_transfer(inode, attr);
+               up_read(&EXT4_I(inode)->xattr_sem);
+
                if (error) {
                        ext4_journal_stop(handle);
                        return error;
@@ -5535,7 +5520,7 @@ static int ext4_index_trans_blocks(struct inode *inode, int lblocks,
  *
  * Also account for superblock, inode, quota and xattr blocks
  */
-int ext4_meta_trans_blocks(struct inode *inode, int lblocks,
+static int ext4_meta_trans_blocks(struct inode *inode, int lblocks,
                                  int pextents)
 {
        ext4_group_t groups, ngroups = ext4_get_groups_count(inode->i_sb);