In a situation like: From: Jan Kara truncate(f, 1024); a = mmap(f, 0, 4096); a[0] = 'a'; truncate(f, 4096); we end up with a dirty page which does not have all blocks allocated / reserved. Fix the problem by using new VFS infrastructure. Signed-off-by: Jan Kara --- fs/ext4/inode.c | 10 ++++++++++ 1 files changed, 10 insertions(+), 0 deletions(-) diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index ebf7bb3..f0f0065 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -3469,6 +3469,7 @@ static int ext4_journalled_set_page_dirty(struct page *page) .sync_page = block_sync_page, .write_begin = ext4_write_begin, .write_end = ext4_ordered_write_end, + .extend_i_size = block_extend_i_size, .bmap = ext4_bmap, .invalidatepage = ext4_invalidatepage, .releasepage = ext4_releasepage, @@ -3484,6 +3485,7 @@ static int ext4_journalled_set_page_dirty(struct page *page) .sync_page = block_sync_page, .write_begin = ext4_write_begin, .write_end = ext4_writeback_write_end, + .extend_i_size = block_extend_i_size, .bmap = ext4_bmap, .invalidatepage = ext4_invalidatepage, .releasepage = ext4_releasepage, @@ -3499,6 +3501,7 @@ static int ext4_journalled_set_page_dirty(struct page *page) .sync_page = block_sync_page, .write_begin = ext4_write_begin, .write_end = ext4_journalled_write_end, + .extend_i_size = block_extend_i_size, .set_page_dirty = ext4_journalled_set_page_dirty, .bmap = ext4_bmap, .invalidatepage = ext4_invalidatepage, @@ -3514,6 +3517,7 @@ static int ext4_journalled_set_page_dirty(struct page *page) .sync_page = block_sync_page, .write_begin = ext4_da_write_begin, .write_end = ext4_da_write_end, + .extend_i_size = block_extend_i_size, .bmap = ext4_bmap, .invalidatepage = ext4_da_invalidatepage, .releasepage = ext4_releasepage, @@ -5379,6 +5383,12 @@ int ext4_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) struct address_space *mapping = inode->i_mapping; /* + * Wait for extending of i_size, after this moment, next truncate / + * write can create holes under us but they writeprotect our page so + * we'll be called again to fill the hole. + */ + block_wait_on_hole_extend(inode, page_offset(page)); + /* * Get i_alloc_sem to stop truncates messing with the inode. We cannot * get i_mutex because we are already holding mmap_sem. */