@@ -5288,51 +5288,44 @@ static int ext4_collapse_range(struct file *file, loff_t offset, loff_t len)
5288
5288
struct inode * inode = file_inode (file );
5289
5289
struct super_block * sb = inode -> i_sb ;
5290
5290
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 ;
5292
5293
handle_t * handle ;
5293
5294
unsigned int credits ;
5294
- loff_t new_size , ioffset ;
5295
+ loff_t start , new_size ;
5295
5296
int ret ;
5296
5297
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 );
5304
5299
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 );
5308
5301
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
+ }
5310
5307
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
+ }
5313
5313
5314
- inode_lock (inode );
5315
5314
/*
5316
5315
* There is no need to overlap collapse range with EOF, in which case
5317
5316
* it is effectively a truncate operation
5318
5317
*/
5319
- if (offset + len >= inode -> i_size ) {
5318
+ if (end >= inode -> i_size ) {
5320
5319
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 ;
5328
5321
}
5329
5322
5330
5323
/* Wait for existing dio to complete */
5331
5324
inode_dio_wait (inode );
5332
5325
5333
5326
ret = file_modified (file );
5334
5327
if (ret )
5335
- goto out_mutex ;
5328
+ goto out ;
5336
5329
5337
5330
/*
5338
5331
* 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)
5342
5335
5343
5336
ret = ext4_break_layouts (inode );
5344
5337
if (ret )
5345
- goto out_mmap ;
5338
+ goto out_invalidate_lock ;
5346
5339
5347
5340
/*
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.
5348
5345
* Need to round down offset to be aligned with page size boundary
5349
5346
* for page size > block size.
5350
5347
*/
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 );
5366
5352
if (ret )
5367
- goto out_mmap ;
5368
- truncate_pagecache (inode , ioffset );
5353
+ goto out_invalidate_lock ;
5354
+
5355
+ truncate_pagecache (inode , start );
5369
5356
5370
5357
credits = ext4_writepage_trans_blocks (inode );
5371
5358
handle = ext4_journal_start (inode , EXT4_HT_TRUNCATE , credits );
5372
5359
if (IS_ERR (handle )) {
5373
5360
ret = PTR_ERR (handle );
5374
- goto out_mmap ;
5361
+ goto out_invalidate_lock ;
5375
5362
}
5376
5363
ext4_fc_mark_ineligible (sb , EXT4_FC_REASON_FALLOC_RANGE , handle );
5377
5364
5365
+ start_lblk = offset >> inode -> i_blkbits ;
5366
+ end_lblk = (offset + len ) >> inode -> i_blkbits ;
5367
+
5378
5368
down_write (& EXT4_I (inode )-> i_data_sem );
5379
5369
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 );
5381
5371
5382
- ret = ext4_ext_remove_space (inode , punch_start , punch_stop - 1 );
5372
+ ret = ext4_ext_remove_space (inode , start_lblk , end_lblk - 1 );
5383
5373
if (ret ) {
5384
5374
up_write (& EXT4_I (inode )-> i_data_sem );
5385
- goto out_stop ;
5375
+ goto out_handle ;
5386
5376
}
5387
5377
ext4_discard_preallocations (inode );
5388
5378
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 );
5391
5381
if (ret ) {
5392
5382
up_write (& EXT4_I (inode )-> i_data_sem );
5393
- goto out_stop ;
5383
+ goto out_handle ;
5394
5384
}
5395
5385
5396
5386
new_size = inode -> i_size - len ;
5397
5387
i_size_write (inode , new_size );
5398
5388
EXT4_I (inode )-> i_disksize = new_size ;
5399
5389
5400
5390
up_write (& EXT4_I (inode )-> i_data_sem );
5401
- if (IS_SYNC (inode ))
5402
- ext4_handle_sync (handle );
5403
5391
ret = ext4_mark_inode_dirty (handle , inode );
5392
+ if (ret )
5393
+ goto out_handle ;
5394
+
5404
5395
ext4_update_inode_fsync_trans (handle , inode , 1 );
5396
+ if (IS_SYNC (inode ))
5397
+ ext4_handle_sync (handle );
5405
5398
5406
- out_stop :
5399
+ out_handle :
5407
5400
ext4_journal_stop (handle );
5408
- out_mmap :
5401
+ out_invalidate_lock :
5409
5402
filemap_invalidate_unlock (mapping );
5410
- out_mutex :
5403
+ out :
5411
5404
inode_unlock (inode );
5412
5405
return ret ;
5413
5406
}
0 commit comments