@@ -5288,51 +5288,44 @@ static int ext4_collapse_range(struct file *file, loff_t offset, loff_t len)
52885288 struct inode * inode = file_inode (file );
52895289 struct super_block * sb = inode -> i_sb ;
52905290 struct address_space * mapping = inode -> i_mapping ;
5291- ext4_lblk_t punch_start , punch_stop ;
5291+ loff_t end = offset + len ;
5292+ ext4_lblk_t start_lblk , end_lblk ;
52925293 handle_t * handle ;
52935294 unsigned int credits ;
5294- loff_t new_size , ioffset ;
5295+ loff_t start , new_size ;
52955296 int ret ;
52965297
5297- /*
5298- * We need to test this early because xfstests assumes that a
5299- * collapse range of (0, 1) will return EOPNOTSUPP if the file
5300- * system does not support collapse range.
5301- */
5302- if (!ext4_test_inode_flag (inode , EXT4_INODE_EXTENTS ))
5303- return - EOPNOTSUPP ;
5298+ trace_ext4_collapse_range (inode , offset , len );
53045299
5305- /* Collapse range works only on fs cluster size aligned regions. */
5306- if (!IS_ALIGNED (offset | len , EXT4_CLUSTER_SIZE (sb )))
5307- return - EINVAL ;
5300+ inode_lock (inode );
53085301
5309- trace_ext4_collapse_range (inode , offset , len );
5302+ /* Currently just for extent based files */
5303+ if (!ext4_test_inode_flag (inode , EXT4_INODE_EXTENTS )) {
5304+ ret = - EOPNOTSUPP ;
5305+ goto out ;
5306+ }
53105307
5311- punch_start = offset >> EXT4_BLOCK_SIZE_BITS (sb );
5312- punch_stop = (offset + len ) >> EXT4_BLOCK_SIZE_BITS (sb );
5308+ /* Collapse range works only on fs cluster size aligned regions. */
5309+ if (!IS_ALIGNED (offset | len , EXT4_CLUSTER_SIZE (sb ))) {
5310+ ret = - EINVAL ;
5311+ goto out ;
5312+ }
53135313
5314- inode_lock (inode );
53155314 /*
53165315 * There is no need to overlap collapse range with EOF, in which case
53175316 * it is effectively a truncate operation
53185317 */
5319- if (offset + len >= inode -> i_size ) {
5318+ if (end >= inode -> i_size ) {
53205319 ret = - EINVAL ;
5321- goto out_mutex ;
5322- }
5323-
5324- /* Currently just for extent based files */
5325- if (!ext4_test_inode_flag (inode , EXT4_INODE_EXTENTS )) {
5326- ret = - EOPNOTSUPP ;
5327- goto out_mutex ;
5320+ goto out ;
53285321 }
53295322
53305323 /* Wait for existing dio to complete */
53315324 inode_dio_wait (inode );
53325325
53335326 ret = file_modified (file );
53345327 if (ret )
5335- goto out_mutex ;
5328+ goto out ;
53365329
53375330 /*
53385331 * Prevent page faults from reinstantiating pages we have released from
@@ -5342,72 +5335,72 @@ static int ext4_collapse_range(struct file *file, loff_t offset, loff_t len)
53425335
53435336 ret = ext4_break_layouts (inode );
53445337 if (ret )
5345- goto out_mmap ;
5338+ goto out_invalidate_lock ;
53465339
53475340 /*
5341+ * Write tail of the last page before removed range and data that
5342+ * will be shifted since they will get removed from the page cache
5343+ * below. We are also protected from pages becoming dirty by
5344+ * i_rwsem and invalidate_lock.
53485345 * Need to round down offset to be aligned with page size boundary
53495346 * for page size > block size.
53505347 */
5351- ioffset = round_down (offset , PAGE_SIZE );
5352- /*
5353- * Write tail of the last page before removed range since it will get
5354- * removed from the page cache below.
5355- */
5356- ret = filemap_write_and_wait_range (mapping , ioffset , offset );
5357- if (ret )
5358- goto out_mmap ;
5359- /*
5360- * Write data that will be shifted to preserve them when discarding
5361- * page cache below. We are also protected from pages becoming dirty
5362- * by i_rwsem and invalidate_lock.
5363- */
5364- ret = filemap_write_and_wait_range (mapping , offset + len ,
5365- LLONG_MAX );
5348+ start = round_down (offset , PAGE_SIZE );
5349+ ret = filemap_write_and_wait_range (mapping , start , offset );
5350+ if (!ret )
5351+ ret = filemap_write_and_wait_range (mapping , end , LLONG_MAX );
53665352 if (ret )
5367- goto out_mmap ;
5368- truncate_pagecache (inode , ioffset );
5353+ goto out_invalidate_lock ;
5354+
5355+ truncate_pagecache (inode , start );
53695356
53705357 credits = ext4_writepage_trans_blocks (inode );
53715358 handle = ext4_journal_start (inode , EXT4_HT_TRUNCATE , credits );
53725359 if (IS_ERR (handle )) {
53735360 ret = PTR_ERR (handle );
5374- goto out_mmap ;
5361+ goto out_invalidate_lock ;
53755362 }
53765363 ext4_fc_mark_ineligible (sb , EXT4_FC_REASON_FALLOC_RANGE , handle );
53775364
5365+ start_lblk = offset >> inode -> i_blkbits ;
5366+ end_lblk = (offset + len ) >> inode -> i_blkbits ;
5367+
53785368 down_write (& EXT4_I (inode )-> i_data_sem );
53795369 ext4_discard_preallocations (inode );
5380- ext4_es_remove_extent (inode , punch_start , EXT_MAX_BLOCKS - punch_start );
5370+ ext4_es_remove_extent (inode , start_lblk , EXT_MAX_BLOCKS - start_lblk );
53815371
5382- ret = ext4_ext_remove_space (inode , punch_start , punch_stop - 1 );
5372+ ret = ext4_ext_remove_space (inode , start_lblk , end_lblk - 1 );
53835373 if (ret ) {
53845374 up_write (& EXT4_I (inode )-> i_data_sem );
5385- goto out_stop ;
5375+ goto out_handle ;
53865376 }
53875377 ext4_discard_preallocations (inode );
53885378
5389- ret = ext4_ext_shift_extents (inode , handle , punch_stop ,
5390- punch_stop - punch_start , SHIFT_LEFT );
5379+ ret = ext4_ext_shift_extents (inode , handle , end_lblk ,
5380+ end_lblk - start_lblk , SHIFT_LEFT );
53915381 if (ret ) {
53925382 up_write (& EXT4_I (inode )-> i_data_sem );
5393- goto out_stop ;
5383+ goto out_handle ;
53945384 }
53955385
53965386 new_size = inode -> i_size - len ;
53975387 i_size_write (inode , new_size );
53985388 EXT4_I (inode )-> i_disksize = new_size ;
53995389
54005390 up_write (& EXT4_I (inode )-> i_data_sem );
5401- if (IS_SYNC (inode ))
5402- ext4_handle_sync (handle );
54035391 ret = ext4_mark_inode_dirty (handle , inode );
5392+ if (ret )
5393+ goto out_handle ;
5394+
54045395 ext4_update_inode_fsync_trans (handle , inode , 1 );
5396+ if (IS_SYNC (inode ))
5397+ ext4_handle_sync (handle );
54055398
5406- out_stop :
5399+ out_handle :
54075400 ext4_journal_stop (handle );
5408- out_mmap :
5401+ out_invalidate_lock :
54095402 filemap_invalidate_unlock (mapping );
5410- out_mutex :
5403+ out :
54115404 inode_unlock (inode );
54125405 return ret ;
54135406}
0 commit comments