Skip to content

Commit 783ae44

Browse files
jankaratytso
authored andcommitted
ext4: Fix special handling of journalled data from extent zeroing
The handling of journalled data in ext4_zero_range() is incomplete. We do not need to commit running transaction but we rather need to checkpoint pages with journalled data. If we don't, journal tail can be advanced beyond transaction containing the journalled data and if we then crash before committing the transaction doing the zeroing we will have inconsistent (too old) data in the file. Make sure file pages with journalled data are properly checkpointed before removing them from the page cache. Signed-off-by: Jan Kara <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Theodore Ts'o <[email protected]>
1 parent c000dfe commit 783ae44

File tree

1 file changed

+14
-7
lines changed

1 file changed

+14
-7
lines changed

fs/ext4/extents.c

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4526,13 +4526,6 @@ static long ext4_zero_range(struct file *file, loff_t offset,
45264526

45274527
trace_ext4_zero_range(inode, offset, len, mode);
45284528

4529-
/* Call ext4_force_commit to flush all data in case of data=journal. */
4530-
if (ext4_should_journal_data(inode)) {
4531-
ret = ext4_force_commit(inode->i_sb);
4532-
if (ret)
4533-
return ret;
4534-
}
4535-
45364529
/*
45374530
* Round up offset. This is not fallocate, we need to zero out
45384531
* blocks, so convert interior block aligned part of the range to
@@ -4616,6 +4609,20 @@ static long ext4_zero_range(struct file *file, loff_t offset,
46164609
filemap_invalidate_unlock(mapping);
46174610
goto out_mutex;
46184611
}
4612+
4613+
/*
4614+
* For journalled data we need to write (and checkpoint) pages
4615+
* before discarding page cache to avoid inconsitent data on
4616+
* disk in case of crash before zeroing trans is committed.
4617+
*/
4618+
if (ext4_should_journal_data(inode)) {
4619+
ret = filemap_write_and_wait_range(mapping, start, end);
4620+
if (ret) {
4621+
filemap_invalidate_unlock(mapping);
4622+
goto out_mutex;
4623+
}
4624+
}
4625+
46194626
/* Now release the pages and zero block aligned part of pages */
46204627
truncate_pagecache_range(inode, start, end - 1);
46214628
inode->i_mtime = inode->i_ctime = current_time(inode);

0 commit comments

Comments
 (0)