On Sat, Jan 27, 2024 at 09:58:01AM +0800, Zhang Yi wrote: > From: Zhang Yi <yi.zhang@xxxxxxxxxx> > > ext4_da_map_blocks() only hold i_data_sem in shared mode and i_rwsem > when inserting delalloc extents, it could be raced by another querying > path of ext4_map_blocks() without i_rwsem, .e.g buffered read path. > Suppose we buffered read a file containing just a hole, and without any > cached extents tree, then it is raced by another delayed buffered write > to the same area or the near area belongs to the same hole, and the new > delalloc extent could be overwritten to a hole extent. > > pread() pwrite() > filemap_read_folio() > ext4_mpage_readpages() > ext4_map_blocks() > down_read(i_data_sem) > ext4_ext_determine_hole() > //find hole > ext4_ext_put_gap_in_cache() > ext4_es_find_extent_range() > //no delalloc extent > ext4_da_map_blocks() > down_read(i_data_sem) > ext4_insert_delayed_block() > //insert delalloc extent > ext4_es_insert_extent() > //overwrite delalloc extent to hole > > This race could lead to inconsistent delalloc extents tree and > incorrect reserved space counter. Fix this by converting to hold > i_data_sem in exclusive mode when adding a new delalloc extent in > ext4_da_map_blocks(). > > Cc: stable@xxxxxxxxxxxxxxx > Signed-off-by: Zhang Yi <yi.zhang@xxxxxxxxxx> > Suggested-by: Jan Kara <jack@xxxxxxx> > Reviewed-by: Jan Kara <jack@xxxxxxx> Thanks, applied. - Ted