On Thu, May 25, 2017 at 10:43:13AM +0200, Jan Kara wrote: > When ext4_map_blocks() is called with EXT4_GET_BLOCKS_ZERO to zero-out > allocated blocks and these blocks are actually converted from unwritten > extent the following race can happen: > > CPU0 CPU1 > > page fault page fault > ... ... > ext4_map_blocks() > ext4_ext_map_blocks() > ext4_ext_handle_unwritten_extents() > ext4_ext_convert_to_initialized() > - zero out converted extent > ext4_zeroout_es() > - inserts extent as initialized in status tree > > ext4_map_blocks() > ext4_es_lookup_extent() > - finds initialized extent > write data > ext4_issue_zeroout() > - zeroes out new extent overwriting data > > This problem can be reproduced by generic/340 for the fallocated case > for the last block in the file. > > Fix the problem by avoiding zeroing out the area we are mapping with > ext4_map_blocks() in ext4_ext_convert_to_initialized(). It is pointless > to zero out this area in the first place as the caller asked us to > convert the area to initialized because he is just going to write data > there before the transaction finishes. To achieve this we delete the > special case of zeroing out full extent as that will be handled by the > cases below zeroing only the part of the extent that needs it. We also > instruct ext4_split_extent() that the middle of extent being split > contains data so that ext4_split_extent_at() cannot zero out full extent > in case of ENOSPC. > > CC: stable@xxxxxxxxxxxxxxx > Fixes: 12735f881952c32b31bc4e433768f18489f79ec9 > Signed-off-by: Jan Kara <jack@xxxxxxx> Thanks, applied. - Ted