@@ -4568,7 +4568,6 @@ static long ext4_zero_range(struct file *file, loff_t offset,
loff_t len, int mode)
{
struct inode *inode = file_inode(file);
- struct address_space *mapping = file->f_mapping;
handle_t *handle = NULL;
loff_t new_size = 0;
loff_t end = offset + len;
@@ -4592,23 +4591,6 @@ static long ext4_zero_range(struct file *file, loff_t offset,
return ret;
}
- /* Wait all existing dio workers, newcomers will block on i_rwsem */
- inode_dio_wait(inode);
-
- ret = file_modified(file);
- if (ret)
- return ret;
-
- /*
- * Prevent page faults from reinstantiating pages we have released
- * from page cache.
- */
- filemap_invalidate_lock(mapping);
-
- ret = ext4_break_layouts(inode);
- if (ret)
- goto out_invalidate_lock;
-
flags = EXT4_GET_BLOCKS_CREATE_UNWRIT_EXT;
/* Preallocate the range including the unaligned edges */
if (!IS_ALIGNED(offset | end, blocksize)) {
@@ -4618,17 +4600,17 @@ static long ext4_zero_range(struct file *file, loff_t offset,
ret = ext4_alloc_file_blocks(file, alloc_lblk, len_lblk,
new_size, flags);
if (ret)
- goto out_invalidate_lock;
+ return ret;
}
ret = ext4_update_disksize_before_punch(inode, offset, len);
if (ret)
- goto out_invalidate_lock;
+ return ret;
/* Now release the pages and zero block aligned part of pages */
ret = ext4_truncate_page_cache_block_range(inode, offset, end);
if (ret)
- goto out_invalidate_lock;
+ return ret;
/* Zero range excluding the unaligned edges */
start_lblk = EXT4_B_TO_LBLK(inode, offset);
@@ -4640,11 +4622,11 @@ static long ext4_zero_range(struct file *file, loff_t offset,
ret = ext4_alloc_file_blocks(file, start_lblk, zero_blks,
new_size, flags);
if (ret)
- goto out_invalidate_lock;
+ return ret;
}
/* Finish zeroing out if it doesn't contain partial block */
if (IS_ALIGNED(offset | end, blocksize))
- goto out_invalidate_lock;
+ return ret;
/*
* In worst case we have to writeout two nonadjacent unwritten
@@ -4657,7 +4639,7 @@ static long ext4_zero_range(struct file *file, loff_t offset,
if (IS_ERR(handle)) {
ret = PTR_ERR(handle);
ext4_std_error(inode->i_sb, ret);
- goto out_invalidate_lock;
+ return ret;
}
/* Zero out partial block at the edges of the range */
@@ -4677,8 +4659,6 @@ static long ext4_zero_range(struct file *file, loff_t offset,
out_handle:
ext4_journal_stop(handle);
-out_invalidate_lock:
- filemap_invalidate_unlock(mapping);
return ret;
}
@@ -4711,13 +4691,6 @@ static long ext4_do_fallocate(struct file *file, loff_t offset,
goto out;
}
- /* Wait all existing dio workers, newcomers will block on i_rwsem */
- inode_dio_wait(inode);
-
- ret = file_modified(file);
- if (ret)
- goto out;
-
ret = ext4_alloc_file_blocks(file, start_lblk, len_lblk, new_size,
EXT4_GET_BLOCKS_CREATE_UNWRIT_EXT);
if (ret)
@@ -4742,6 +4715,7 @@ static long ext4_do_fallocate(struct file *file, loff_t offset,
long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
{
struct inode *inode = file_inode(file);
+ struct address_space *mapping = file->f_mapping;
int ret;
/*
@@ -4765,6 +4739,29 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
if (ret)
goto out_inode_lock;
+ /* Wait all existing dio workers, newcomers will block on i_rwsem */
+ inode_dio_wait(inode);
+
+ ret = file_modified(file);
+ if (ret)
+ return ret;
+
+ if ((mode & FALLOC_FL_MODE_MASK) == FALLOC_FL_ALLOCATE_RANGE) {
+ ret = ext4_do_fallocate(file, offset, len, mode);
+ goto out_inode_lock;
+ }
+
+ /*
+ * Follow-up operations will drop page cache, hold invalidate lock
+ * to prevent page faults from reinstantiating pages we have
+ * released from page cache.
+ */
+ filemap_invalidate_lock(mapping);
+
+ ret = ext4_break_layouts(inode);
+ if (ret)
+ goto out_invalidate_lock;
+
if (mode & FALLOC_FL_PUNCH_HOLE)
ret = ext4_punch_hole(file, offset, len);
else if (mode & FALLOC_FL_COLLAPSE_RANGE)
@@ -4774,7 +4771,10 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
else if (mode & FALLOC_FL_ZERO_RANGE)
ret = ext4_zero_range(file, offset, len, mode);
else
- ret = ext4_do_fallocate(file, offset, len, mode);
+ ret = -EOPNOTSUPP;
+
+out_invalidate_lock:
+ filemap_invalidate_unlock(mapping);
out_inode_lock:
inode_unlock(inode);
return ret;
@@ -5301,23 +5301,6 @@ static int ext4_collapse_range(struct file *file, loff_t offset, loff_t len)
if (end >= inode->i_size)
return -EINVAL;
- /* Wait for existing dio to complete */
- inode_dio_wait(inode);
-
- ret = file_modified(file);
- if (ret)
- return ret;
-
- /*
- * Prevent page faults from reinstantiating pages we have released from
- * page cache.
- */
- filemap_invalidate_lock(mapping);
-
- ret = ext4_break_layouts(inode);
- if (ret)
- goto out_invalidate_lock;
-
/*
* Write tail of the last page before removed range and data that
* will be shifted since they will get removed from the page cache
@@ -5331,16 +5314,15 @@ static int ext4_collapse_range(struct file *file, loff_t offset, loff_t len)
if (!ret)
ret = filemap_write_and_wait_range(mapping, end, LLONG_MAX);
if (ret)
- goto out_invalidate_lock;
+ return ret;
truncate_pagecache(inode, start);
credits = ext4_writepage_trans_blocks(inode);
handle = ext4_journal_start(inode, EXT4_HT_TRUNCATE, credits);
- if (IS_ERR(handle)) {
- ret = PTR_ERR(handle);
- goto out_invalidate_lock;
- }
+ if (IS_ERR(handle))
+ return PTR_ERR(handle);
+
ext4_fc_mark_ineligible(sb, EXT4_FC_REASON_FALLOC_RANGE, handle);
start_lblk = offset >> inode->i_blkbits;
@@ -5379,8 +5361,6 @@ static int ext4_collapse_range(struct file *file, loff_t offset, loff_t len)
out_handle:
ext4_journal_stop(handle);
-out_invalidate_lock:
- filemap_invalidate_unlock(mapping);
return ret;
}
@@ -5421,23 +5401,6 @@ static int ext4_insert_range(struct file *file, loff_t offset, loff_t len)
if (len > inode->i_sb->s_maxbytes - inode->i_size)
return -EFBIG;
- /* Wait for existing dio to complete */
- inode_dio_wait(inode);
-
- ret = file_modified(file);
- if (ret)
- return ret;
-
- /*
- * Prevent page faults from reinstantiating pages we have released from
- * page cache.
- */
- filemap_invalidate_lock(mapping);
-
- ret = ext4_break_layouts(inode);
- if (ret)
- goto out_invalidate_lock;
-
/*
* Write out all dirty pages. Need to round down to align start offset
* to page size boundary for page size > block size.
@@ -5445,16 +5408,15 @@ static int ext4_insert_range(struct file *file, loff_t offset, loff_t len)
start = round_down(offset, PAGE_SIZE);
ret = filemap_write_and_wait_range(mapping, start, LLONG_MAX);
if (ret)
- goto out_invalidate_lock;
+ return ret;
truncate_pagecache(inode, start);
credits = ext4_writepage_trans_blocks(inode);
handle = ext4_journal_start(inode, EXT4_HT_TRUNCATE, credits);
- if (IS_ERR(handle)) {
- ret = PTR_ERR(handle);
- goto out_invalidate_lock;
- }
+ if (IS_ERR(handle))
+ return PTR_ERR(handle);
+
ext4_fc_mark_ineligible(sb, EXT4_FC_REASON_FALLOC_RANGE, handle);
/* Expand file to avoid data loss if there is error while shifting */
@@ -5525,8 +5487,6 @@ static int ext4_insert_range(struct file *file, loff_t offset, loff_t len)
out_handle:
ext4_journal_stop(handle);
-out_invalidate_lock:
- filemap_invalidate_unlock(mapping);
return ret;
}
@@ -4010,7 +4010,6 @@ int ext4_punch_hole(struct file *file, loff_t offset, loff_t length)
struct inode *inode = file_inode(file);
struct super_block *sb = inode->i_sb;
ext4_lblk_t start_lblk, end_lblk;
- struct address_space *mapping = inode->i_mapping;
loff_t max_end = EXT4_SB(sb)->s_bitmap_maxbytes - sb->s_blocksize;
loff_t end = offset + length;
handle_t *handle;
@@ -4045,31 +4044,15 @@ int ext4_punch_hole(struct file *file, loff_t offset, loff_t length)
return ret;
}
- /* Wait all existing dio workers, newcomers will block on i_rwsem */
- inode_dio_wait(inode);
-
- ret = file_modified(file);
- if (ret)
- return ret;
-
- /*
- * Prevent page faults from reinstantiating pages we have released from
- * page cache.
- */
- filemap_invalidate_lock(mapping);
-
- ret = ext4_break_layouts(inode);
- if (ret)
- goto out_invalidate_lock;
ret = ext4_update_disksize_before_punch(inode, offset, length);
if (ret)
- goto out_invalidate_lock;
+ return ret;
/* Now release the pages and zero block aligned part of pages*/
ret = ext4_truncate_page_cache_block_range(inode, offset, end);
if (ret)
- goto out_invalidate_lock;
+ return ret;
if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))
credits = ext4_writepage_trans_blocks(inode);
@@ -4079,7 +4062,7 @@ int ext4_punch_hole(struct file *file, loff_t offset, loff_t length)
if (IS_ERR(handle)) {
ret = PTR_ERR(handle);
ext4_std_error(sb, ret);
- goto out_invalidate_lock;
+ return ret;
}
ret = ext4_zero_partial_blocks(handle, inode, offset, length);
@@ -4124,8 +4107,6 @@ int ext4_punch_hole(struct file *file, loff_t offset, loff_t length)
ext4_handle_sync(handle);
out_handle:
ext4_journal_stop(handle);
-out_invalidate_lock:
- filemap_invalidate_unlock(mapping);
return ret;
}