ext4_std_error(inode->i_sb, err);
 }
 
-static void ext4_falloc_update_inode(struct inode *inode,
-                               int mode, loff_t new_size, int update_ctime)
-{
-       struct timespec now;
-
-       if (update_ctime) {
-               now = current_fs_time(inode->i_sb);
-               if (!timespec_equal(&inode->i_ctime, &now))
-                       inode->i_ctime = now;
-       }
-       /*
-        * Update only when preallocation was requested beyond
-        * the file size.
-        */
-       if (!(mode & FALLOC_FL_KEEP_SIZE)) {
-               if (new_size > i_size_read(inode))
-                       i_size_write(inode, new_size);
-               if (new_size > EXT4_I(inode)->i_disksize)
-                       ext4_update_i_disksize(inode, new_size);
-       } else {
-               /*
-                * Mark that we allocate beyond EOF so the subsequent truncate
-                * can proceed even if the new size is the same as i_size.
-                */
-               if (new_size > i_size_read(inode))
-                       ext4_set_inode_flag(inode, EXT4_INODE_EOFBLOCKS);
-       }
-
-}
-
 /*
  * preallocate space for a file. This implements ext4's fallocate file
  * operation, which gets called from sys_fallocate system call.
 {
        struct inode *inode = file_inode(file);
        handle_t *handle;
-       loff_t new_size;
+       loff_t new_size = 0;
        unsigned int max_blocks;
        int ret = 0;
        int ret2 = 0;
        int retries = 0;
        int flags;
        struct ext4_map_blocks map;
+       struct timespec tv;
        unsigned int credits, blkbits = inode->i_blkbits;
 
        /* Return error if mode is not supported */
         */
        credits = ext4_chunk_trans_blocks(inode, max_blocks);
        mutex_lock(&inode->i_mutex);
-       ret = inode_newsize_ok(inode, (len + offset));
-       if (ret) {
-               mutex_unlock(&inode->i_mutex);
-               trace_ext4_fallocate_exit(inode, offset, max_blocks, ret);
-               return ret;
+
+       if (!(mode & FALLOC_FL_KEEP_SIZE) &&
+            offset + len > i_size_read(inode)) {
+               new_size = offset + len;
+               ret = inode_newsize_ok(inode, new_size);
+               if (ret)
+                       goto out;
        }
+
        flags = EXT4_GET_BLOCKS_CREATE_UNINIT_EXT;
        if (mode & FALLOC_FL_KEEP_SIZE)
                flags |= EXT4_GET_BLOCKS_KEEP_SIZE;
                }
                ret = ext4_map_blocks(handle, inode, &map, flags);
                if (ret <= 0) {
-#ifdef EXT4FS_DEBUG
-                       ext4_warning(inode->i_sb,
-                                    "inode #%lu: block %u: len %u: "
-                                    "ext4_ext_map_blocks returned %d",
-                                    inode->i_ino, map.m_lblk,
-                                    map.m_len, ret);
-#endif
+                       ext4_debug("inode #%lu: block %u: len %u: "
+                                  "ext4_ext_map_blocks returned %d",
+                                  inode->i_ino, map.m_lblk,
+                                  map.m_len, ret);
                        ext4_mark_inode_dirty(handle, inode);
                        ret2 = ext4_journal_stop(handle);
                        break;
                }
-               if ((map.m_lblk + ret) >= (EXT4_BLOCK_ALIGN(offset + len,
-                                               blkbits) >> blkbits))
-                       new_size = offset + len;
-               else
-                       new_size = ((loff_t) map.m_lblk + ret) << blkbits;
-
-               ext4_falloc_update_inode(inode, mode, new_size,
-                                        (map.m_flags & EXT4_MAP_NEW));
-               ext4_mark_inode_dirty(handle, inode);
-               if ((file->f_flags & O_SYNC) && ret >= max_blocks)
-                       ext4_handle_sync(handle);
                ret2 = ext4_journal_stop(handle);
                if (ret2)
                        break;
                ret = 0;
                goto retry;
        }
+
+       handle = ext4_journal_start(inode, EXT4_HT_INODE, 2);
+       if (IS_ERR(handle))
+               goto out;
+
+       tv = inode->i_ctime = ext4_current_time(inode);
+
+       if (ret > 0 && new_size) {
+               if (new_size > i_size_read(inode)) {
+                       i_size_write(inode, new_size);
+                       inode->i_mtime = tv;
+               }
+               if (new_size > EXT4_I(inode)->i_disksize)
+                       ext4_update_i_disksize(inode, new_size);
+       } else if (ret > 0 && !new_size) {
+               /*
+               * Mark that we allocate beyond EOF so the subsequent truncate
+               * can proceed even if the new size is the same as i_size.
+               */
+               if ((offset + len) > i_size_read(inode))
+                       ext4_set_inode_flag(inode, EXT4_INODE_EOFBLOCKS);
+       }
+       ext4_mark_inode_dirty(handle, inode);
+       if (file->f_flags & O_SYNC)
+               ext4_handle_sync(handle);
+
+       ext4_journal_stop(handle);
+out:
        mutex_unlock(&inode->i_mutex);
        trace_ext4_fallocate_exit(inode, offset, max_blocks,
                                ret > 0 ? ret2 : ret);