ext4: avoid unnecessary stalls in ext4_evict_inode()
[sfrench/cifs-2.6.git] / fs / ext4 / inode.c
index 5834c4d76be80969125a9c2d56309e990ba07e84..754c2190af3148cd60f1d0a8006918ef3198937a 100644 (file)
@@ -189,6 +189,8 @@ void ext4_evict_inode(struct inode *inode)
 {
        handle_t *handle;
        int err;
+       int extra_credits = 3;
+       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;
 
@@ -238,8 +241,12 @@ void ext4_evict_inode(struct inode *inode)
         * protection against it
         */
        sb_start_intwrite(inode->i_sb);
+
+       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)+3);
+                                ext4_blocks_for_truncate(inode)+extra_credits);
        if (IS_ERR(handle)) {
                ext4_std_error(inode->i_sb, PTR_ERR(handle));
                /*
@@ -271,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, 3)) {
-               err = ext4_journal_extend(handle, 3);
-               if (err > 0)
-                       err = ext4_journal_restart(handle, 3);
-               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;
        }
 
        /*
@@ -317,6 +316,7 @@ void ext4_evict_inode(struct inode *inode)
                ext4_free_inode(handle, inode);
        ext4_journal_stop(handle);
        sb_end_intwrite(inode->i_sb);
+       ext4_xattr_inode_array_free(ea_inode_array);
        return;
 no_delete:
        ext4_clear_inode(inode);        /* We must guarantee clearing of inode... */
@@ -710,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);
@@ -2124,15 +2124,29 @@ static int ext4_writepage(struct page *page,
 static int mpage_submit_page(struct mpage_da_data *mpd, struct page *page)
 {
        int len;
-       loff_t size = i_size_read(mpd->inode);
+       loff_t size;
        int err;
 
        BUG_ON(page->index != mpd->first_page);
+       clear_page_dirty_for_io(page);
+       /*
+        * We have to be very careful here!  Nothing protects writeback path
+        * against i_size changes and the page can be writeably mapped into
+        * page tables. So an application can be growing i_size and writing
+        * data through mmap while writeback runs. clear_page_dirty_for_io()
+        * write-protects our page in page tables and the page cannot get
+        * written to again until we release page lock. So only after
+        * clear_page_dirty_for_io() we are safe to sample i_size for
+        * ext4_bio_write_page() to zero-out tail of the written page. We rely
+        * on the barrier provided by TestClearPageDirty in
+        * clear_page_dirty_for_io() to make sure i_size is really sampled only
+        * after page tables are updated.
+        */
+       size = i_size_read(mpd->inode);
        if (page->index == size >> PAGE_SHIFT)
                len = size & ~PAGE_MASK;
        else
                len = PAGE_SIZE;
-       clear_page_dirty_for_io(page);
        err = ext4_bio_write_page(&mpd->io_submit, page, len, mpd->wbc, false);
        if (!err)
                mpd->wbc->nr_to_write--;
@@ -3412,7 +3426,7 @@ retry:
        bdev = inode->i_sb->s_bdev;
        iomap->bdev = bdev;
        if (blk_queue_dax(bdev->bd_queue))
-               iomap->dax_dev = dax_get_by_host(bdev->bd_disk->disk_name);
+               iomap->dax_dev = fs_dax_get_by_host(bdev->bd_disk->disk_name);
        else
                iomap->dax_dev = NULL;
        iomap->offset = first_block << blkbits;
@@ -3447,7 +3461,7 @@ static int ext4_iomap_end(struct inode *inode, loff_t offset, loff_t length,
        int blkbits = inode->i_blkbits;
        bool truncate = false;
 
-       put_dax(iomap->dax_dev);
+       fs_put_dax(iomap->dax_dev);
        if (!(flags & IOMAP_WRITE) || (flags & IOMAP_FAULT))
                return 0;
 
@@ -3629,9 +3643,6 @@ static ssize_t ext4_direct_IO_write(struct kiocb *iocb, struct iov_iter *iter)
                get_block_func = ext4_dio_get_block_unwritten_async;
                dio_flags = DIO_LOCKING;
        }
-#ifdef CONFIG_EXT4_FS_ENCRYPTION
-       BUG_ON(ext4_encrypted_inode(inode) && S_ISREG(inode->i_mode));
-#endif
        ret = __blockdev_direct_IO(iocb, inode, inode->i_sb->s_bdev, iter,
                                   get_block_func, ext4_end_io_dio, NULL,
                                   dio_flags);
@@ -3713,7 +3724,7 @@ static ssize_t ext4_direct_IO_read(struct kiocb *iocb, struct iov_iter *iter)
         */
        inode_lock_shared(inode);
        ret = filemap_write_and_wait_range(mapping, iocb->ki_pos,
-                                          iocb->ki_pos + count);
+                                          iocb->ki_pos + count - 1);
        if (ret)
                goto out_unlock;
        ret = __blockdev_direct_IO(iocb, inode, inode->i_sb->s_bdev,
@@ -4207,6 +4218,8 @@ int ext4_punch_hole(struct inode *inode, loff_t offset, loff_t length)
 
        inode->i_mtime = inode->i_ctime = current_time(inode);
        ext4_mark_inode_dirty(handle, inode);
+       if (ret >= 0)
+               ext4_update_inode_fsync_trans(handle, inode, 1);
 out_stop:
        ext4_journal_stop(handle);
 out_dio:
@@ -4699,7 +4712,7 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
        if (ext4_has_feature_64bit(sb))
                ei->i_file_acl |=
                        ((__u64)le16_to_cpu(raw_inode->i_file_acl_high)) << 32;
-       inode->i_size = ext4_isize(raw_inode);
+       inode->i_size = ext4_isize(sb, raw_inode);
        if ((size = i_size_read(inode)) < 0) {
                EXT4_ERROR_INODE(inode, "bad i_size value: %lld", size);
                ret = -EFSCORRUPTED;
@@ -4833,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;
 
@@ -5024,7 +5046,7 @@ static int ext4_do_update_inode(handle_t *handle,
                raw_inode->i_file_acl_high =
                        cpu_to_le16(ei->i_file_acl >> 32);
        raw_inode->i_file_acl_lo = cpu_to_le32(ei->i_file_acl);
-       if (ei->i_disksize != ext4_isize(raw_inode)) {
+       if (ei->i_disksize != ext4_isize(inode->i_sb, raw_inode)) {
                ext4_isize_set(raw_inode, ei->i_disksize);
                need_datasync = 1;
        }
@@ -5274,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;
@@ -5637,8 +5666,9 @@ static int ext4_expand_extra_isize(struct inode *inode,
        /* No extended attributes present */
        if (!ext4_test_inode_state(inode, EXT4_STATE_XATTR) ||
            header->h_magic != cpu_to_le32(EXT4_XATTR_MAGIC)) {
-               memset((void *)raw_inode + EXT4_GOOD_OLD_INODE_SIZE, 0,
-                       new_extra_isize);
+               memset((void *)raw_inode + EXT4_GOOD_OLD_INODE_SIZE +
+                      EXT4_I(inode)->i_extra_isize, 0,
+                      new_extra_isize - EXT4_I(inode)->i_extra_isize);
                EXT4_I(inode)->i_extra_isize = new_extra_isize;
                return 0;
        }