summaryrefslogtreecommitdiffstats
path: root/fs/ext4/file.c
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2016-05-13 00:51:15 -0400
committerTheodore Ts'o <tytso@mit.edu>2016-05-13 00:51:15 -0400
commit12735f881952c32b31bc4e433768f18489f79ec9 (patch)
treedd23e6d522644d094af930a68132d8071a5de05c /fs/ext4/file.c
parent914f82a32d026884743fb3de9f6f0a5908a9d5dd (diff)
downloadlinux-stable-12735f881952c32b31bc4e433768f18489f79ec9.tar.gz
linux-stable-12735f881952c32b31bc4e433768f18489f79ec9.tar.bz2
linux-stable-12735f881952c32b31bc4e433768f18489f79ec9.zip
ext4: pre-zero allocated blocks for DAX IO
Currently ext4 treats DAX IO the same way as direct IO. I.e., it allocates unwritten extents before IO is done and converts unwritten extents afterwards. However this way DAX IO can race with page fault to the same area: ext4_ext_direct_IO() dax_fault() dax_io() get_block() - allocates unwritten extent copy_from_iter_pmem() get_block() - converts unwritten block to written and zeroes it out ext4_convert_unwritten_extents() So data written with DAX IO gets lost. Similarly dax_new_buf() called from dax_io() can overwrite data that has been already written to the block via mmap. Fix the problem by using pre-zeroed blocks for DAX IO the same way as we use them for DAX mmap. The downside of this solution is that every allocating write writes each block twice (once zeros, once data). Fixing the race with locking is possible as well however we would need to lock-out faults for the whole range written to by DAX IO. And that is not easy to do without locking-out faults for the whole file which seems too aggressive. Signed-off-by: Jan Kara <jack@suse.cz> Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Diffstat (limited to 'fs/ext4/file.c')
-rw-r--r--fs/ext4/file.c4
1 files changed, 2 insertions, 2 deletions
diff --git a/fs/ext4/file.c b/fs/ext4/file.c
index 3e850b988923..37e28082885a 100644
--- a/fs/ext4/file.c
+++ b/fs/ext4/file.c
@@ -207,7 +207,7 @@ static int ext4_dax_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
if (IS_ERR(handle))
result = VM_FAULT_SIGBUS;
else
- result = __dax_fault(vma, vmf, ext4_dax_mmap_get_block, NULL);
+ result = __dax_fault(vma, vmf, ext4_dax_get_block, NULL);
if (write) {
if (!IS_ERR(handle))
@@ -243,7 +243,7 @@ static int ext4_dax_pmd_fault(struct vm_area_struct *vma, unsigned long addr,
result = VM_FAULT_SIGBUS;
else
result = __dax_pmd_fault(vma, addr, pmd, flags,
- ext4_dax_mmap_get_block, NULL);
+ ext4_dax_get_block, NULL);
if (write) {
if (!IS_ERR(handle))