diff options
author | Jan Kara <jack@suse.cz> | 2016-05-13 00:51:15 -0400 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2016-05-13 00:51:15 -0400 |
commit | 12735f881952c32b31bc4e433768f18489f79ec9 (patch) | |
tree | dd23e6d522644d094af930a68132d8071a5de05c /fs/ext4/file.c | |
parent | 914f82a32d026884743fb3de9f6f0a5908a9d5dd (diff) | |
download | linux-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.c | 4 |
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)) |