ext4: fix incorect journal credits reservation in ext4_zero_range
[firefly-linux-kernel-4.4.55.git] / fs / ext4 / extents.c
index 4da228a0e6d02f3cbd1e680e181f3ed88a82f6f3..0e9de2328bd20d373024eef6aead582805b0c6c6 100644 (file)
@@ -161,6 +161,8 @@ int __ext4_ext_dirty(const char *where, unsigned int line, handle_t *handle,
                     struct inode *inode, struct ext4_ext_path *path)
 {
        int err;
+
+       WARN_ON(!rwsem_is_locked(&EXT4_I(inode)->i_data_sem));
        if (path->p_bh) {
                ext4_extent_block_csum_set(inode, ext_block_hdr(path->p_bh));
                /* path points to block */
@@ -1808,8 +1810,7 @@ static void ext4_ext_try_to_merge_up(handle_t *handle,
 
        brelse(path[1].p_bh);
        ext4_free_blocks(handle, inode, NULL, blk, 1,
-                        EXT4_FREE_BLOCKS_METADATA | EXT4_FREE_BLOCKS_FORGET |
-                        EXT4_FREE_BLOCKS_RESERVE);
+                        EXT4_FREE_BLOCKS_METADATA | EXT4_FREE_BLOCKS_FORGET);
 }
 
 /*
@@ -3253,7 +3254,7 @@ out:
 
 fix_extent_len:
        ex->ee_len = orig_ex.ee_len;
-       ext4_ext_dirty(handle, inode, path + depth);
+       ext4_ext_dirty(handle, inode, path + path->p_depth);
        return err;
 }
 
@@ -4730,6 +4731,7 @@ static long ext4_zero_range(struct file *file, loff_t offset,
        loff_t new_size = 0;
        int ret = 0;
        int flags;
+       int credits;
        int partial;
        loff_t start, end;
        ext4_lblk_t lblk;
@@ -4829,8 +4831,14 @@ static long ext4_zero_range(struct file *file, loff_t offset,
                if (ret)
                        goto out_dio;
        }
-
-       handle = ext4_journal_start(inode, EXT4_HT_MISC, 4);
+       /*
+        * In worst case we have to writeout two nonadjacent unwritten
+        * blocks and update the inode
+        */
+       credits = (2 * ext4_ext_index_trans_blocks(inode, 2)) + 1;
+       if (ext4_should_journal_data(inode))
+               credits += 2;
+       handle = ext4_journal_start(inode, EXT4_HT_MISC, credits);
        if (IS_ERR(handle)) {
                ret = PTR_ERR(handle);
                ext4_std_error(inode->i_sb, ret);
@@ -4838,12 +4846,8 @@ static long ext4_zero_range(struct file *file, loff_t offset,
        }
 
        inode->i_mtime = inode->i_ctime = ext4_current_time(inode);
-
        if (new_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);
+               ext4_update_inode_size(inode, new_size);
        } else {
                /*
                * Mark that we allocate beyond EOF so the subsequent truncate
@@ -4885,7 +4889,6 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
        int ret = 0;
        int flags;
        ext4_lblk_t lblk;
-       struct timespec tv;
        unsigned int blkbits = inode->i_blkbits;
 
        /* Return error if mode is not supported */
@@ -4944,15 +4947,11 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
        if (IS_ERR(handle))
                goto out;
 
-       tv = inode->i_ctime = ext4_current_time(inode);
+       inode->i_ctime = ext4_current_time(inode);
 
        if (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);
+               if (ext4_update_inode_size(inode, new_size) & 0x1)
+                       inode->i_mtime = inode->i_ctime;
        } else {
                /*
                * Mark that we allocate beyond EOF so the subsequent truncate
@@ -5403,16 +5402,13 @@ int ext4_collapse_range(struct inode *inode, loff_t offset, loff_t len)
        int ret;
 
        /* Collapse range works only on fs block size aligned offsets. */
-       if (offset & (EXT4_BLOCK_SIZE(sb) - 1) ||
-           len & (EXT4_BLOCK_SIZE(sb) - 1))
+       if (offset & (EXT4_CLUSTER_SIZE(sb) - 1) ||
+           len & (EXT4_CLUSTER_SIZE(sb) - 1))
                return -EINVAL;
 
        if (!S_ISREG(inode->i_mode))
                return -EINVAL;
 
-       if (EXT4_SB(inode->i_sb)->s_cluster_ratio > 1)
-               return -EOPNOTSUPP;
-
        trace_ext4_collapse_range(inode, offset, len);
 
        punch_start = offset >> EXT4_BLOCK_SIZE_BITS(sb);