@@ -4571,118 +4571,86 @@ static long ext4_zero_range(struct file *file, loff_t offset,
4571
4571
struct inode * inode = file_inode (file );
4572
4572
struct address_space * mapping = file -> f_mapping ;
4573
4573
handle_t * handle = NULL ;
4574
- unsigned int max_blocks ;
4575
4574
loff_t new_size = 0 ;
4576
- int ret = 0 ;
4577
- int flags ;
4578
- int credits ;
4579
- int partial_begin , partial_end ;
4580
- loff_t start , end ;
4581
- ext4_lblk_t lblk ;
4575
+ loff_t end = offset + len ;
4576
+ ext4_lblk_t start_lblk , end_lblk ;
4577
+ unsigned int blocksize = i_blocksize (inode );
4582
4578
unsigned int blkbits = inode -> i_blkbits ;
4579
+ int ret , flags , credits ;
4583
4580
4584
4581
trace_ext4_zero_range (inode , offset , len , mode );
4585
4582
4586
- /*
4587
- * Round up offset. This is not fallocate, we need to zero out
4588
- * blocks, so convert interior block aligned part of the range to
4589
- * unwritten and possibly manually zero out unaligned parts of the
4590
- * range. Here, start and partial_begin are inclusive, end and
4591
- * partial_end are exclusive.
4592
- */
4593
- start = round_up (offset , 1 << blkbits );
4594
- end = round_down ((offset + len ), 1 << blkbits );
4595
-
4596
- if (start < offset || end > offset + len )
4597
- return - EINVAL ;
4598
- partial_begin = offset & ((1 << blkbits ) - 1 );
4599
- partial_end = (offset + len ) & ((1 << blkbits ) - 1 );
4600
-
4601
- lblk = start >> blkbits ;
4602
- max_blocks = (end >> blkbits );
4603
- if (max_blocks < lblk )
4604
- max_blocks = 0 ;
4605
- else
4606
- max_blocks -= lblk ;
4607
-
4608
4583
inode_lock (inode );
4609
4584
4610
4585
/*
4611
4586
* Indirect files do not support unwritten extents
4612
4587
*/
4613
4588
if (!(ext4_test_inode_flag (inode , EXT4_INODE_EXTENTS ))) {
4614
4589
ret = - EOPNOTSUPP ;
4615
- goto out_mutex ;
4590
+ goto out ;
4616
4591
}
4617
4592
4618
4593
if (!(mode & FALLOC_FL_KEEP_SIZE ) &&
4619
- (offset + len > inode -> i_size ||
4620
- offset + len > EXT4_I (inode )-> i_disksize )) {
4621
- new_size = offset + len ;
4594
+ (end > inode -> i_size || end > EXT4_I (inode )-> i_disksize )) {
4595
+ new_size = end ;
4622
4596
ret = inode_newsize_ok (inode , new_size );
4623
4597
if (ret )
4624
- goto out_mutex ;
4598
+ goto out ;
4625
4599
}
4626
4600
4627
- flags = EXT4_GET_BLOCKS_CREATE_UNWRIT_EXT ;
4628
-
4629
4601
/* Wait all existing dio workers, newcomers will block on i_rwsem */
4630
4602
inode_dio_wait (inode );
4631
4603
4632
4604
ret = file_modified (file );
4633
4605
if (ret )
4634
- goto out_mutex ;
4635
-
4636
- /* Preallocate the range including the unaligned edges */
4637
- if (partial_begin || partial_end ) {
4638
- ret = ext4_alloc_file_blocks (file ,
4639
- round_down (offset , 1 << blkbits ) >> blkbits ,
4640
- (round_up ((offset + len ), 1 << blkbits ) -
4641
- round_down (offset , 1 << blkbits )) >> blkbits ,
4642
- new_size , flags );
4643
- if (ret )
4644
- goto out_mutex ;
4606
+ goto out ;
4645
4607
4646
- }
4608
+ /*
4609
+ * Prevent page faults from reinstantiating pages we have released
4610
+ * from page cache.
4611
+ */
4612
+ filemap_invalidate_lock (mapping );
4647
4613
4648
- /* Zero range excluding the unaligned edges */
4649
- if (max_blocks > 0 ) {
4650
- flags |= (EXT4_GET_BLOCKS_CONVERT_UNWRITTEN |
4651
- EXT4_EX_NOCACHE );
4614
+ ret = ext4_break_layouts (inode );
4615
+ if (ret )
4616
+ goto out_invalidate_lock ;
4652
4617
4653
- /*
4654
- * Prevent page faults from reinstantiating pages we have
4655
- * released from page cache.
4656
- */
4657
- filemap_invalidate_lock ( mapping );
4618
+ flags = EXT4_GET_BLOCKS_CREATE_UNWRIT_EXT ;
4619
+ /* Preallocate the range including the unaligned edges */
4620
+ if (! IS_ALIGNED ( offset | end , blocksize )) {
4621
+ ext4_lblk_t alloc_lblk = offset >> blkbits ;
4622
+ ext4_lblk_t len_lblk = EXT4_MAX_BLOCKS ( len , offset , blkbits );
4658
4623
4659
- ret = ext4_break_layouts ( inode );
4660
- if ( ret ) {
4661
- filemap_invalidate_unlock ( mapping );
4662
- goto out_mutex ;
4663
- }
4624
+ ret = ext4_alloc_file_blocks ( file , alloc_lblk , len_lblk ,
4625
+ new_size , flags );
4626
+ if ( ret )
4627
+ goto out_invalidate_lock ;
4628
+ }
4664
4629
4665
- ret = ext4_update_disksize_before_punch (inode , offset , len );
4666
- if (ret ) {
4667
- filemap_invalidate_unlock (mapping );
4668
- goto out_mutex ;
4669
- }
4630
+ ret = ext4_update_disksize_before_punch (inode , offset , len );
4631
+ if (ret )
4632
+ goto out_invalidate_lock ;
4670
4633
4671
- /* Now release the pages and zero block aligned part of pages */
4672
- ret = ext4_truncate_page_cache_block_range (inode , start , end );
4673
- if (ret ) {
4674
- filemap_invalidate_unlock (mapping );
4675
- goto out_mutex ;
4676
- }
4634
+ /* Now release the pages and zero block aligned part of pages */
4635
+ ret = ext4_truncate_page_cache_block_range (inode , offset , end );
4636
+ if (ret )
4637
+ goto out_invalidate_lock ;
4677
4638
4678
- ret = ext4_alloc_file_blocks (file , lblk , max_blocks , new_size ,
4679
- flags );
4680
- filemap_invalidate_unlock (mapping );
4639
+ /* Zero range excluding the unaligned edges */
4640
+ start_lblk = EXT4_B_TO_LBLK (inode , offset );
4641
+ end_lblk = end >> blkbits ;
4642
+ if (end_lblk > start_lblk ) {
4643
+ ext4_lblk_t zero_blks = end_lblk - start_lblk ;
4644
+
4645
+ flags |= (EXT4_GET_BLOCKS_CONVERT_UNWRITTEN | EXT4_EX_NOCACHE );
4646
+ ret = ext4_alloc_file_blocks (file , start_lblk , zero_blks ,
4647
+ new_size , flags );
4681
4648
if (ret )
4682
- goto out_mutex ;
4649
+ goto out_invalidate_lock ;
4683
4650
}
4684
- if (!partial_begin && !partial_end )
4685
- goto out_mutex ;
4651
+ /* Finish zeroing out if it doesn't contain partial block */
4652
+ if (IS_ALIGNED (offset | end , blocksize ))
4653
+ goto out_invalidate_lock ;
4686
4654
4687
4655
/*
4688
4656
* In worst case we have to writeout two nonadjacent unwritten
@@ -4695,25 +4663,29 @@ static long ext4_zero_range(struct file *file, loff_t offset,
4695
4663
if (IS_ERR (handle )) {
4696
4664
ret = PTR_ERR (handle );
4697
4665
ext4_std_error (inode -> i_sb , ret );
4698
- goto out_mutex ;
4666
+ goto out_invalidate_lock ;
4699
4667
}
4700
4668
4669
+ /* Zero out partial block at the edges of the range */
4670
+ ret = ext4_zero_partial_blocks (handle , inode , offset , len );
4671
+ if (ret )
4672
+ goto out_handle ;
4673
+
4701
4674
if (new_size )
4702
4675
ext4_update_inode_size (inode , new_size );
4703
4676
ret = ext4_mark_inode_dirty (handle , inode );
4704
4677
if (unlikely (ret ))
4705
4678
goto out_handle ;
4706
- /* Zero out partial block at the edges of the range */
4707
- ret = ext4_zero_partial_blocks (handle , inode , offset , len );
4708
- if (ret >= 0 )
4709
- ext4_update_inode_fsync_trans (handle , inode , 1 );
4710
4679
4680
+ ext4_update_inode_fsync_trans (handle , inode , 1 );
4711
4681
if (file -> f_flags & O_SYNC )
4712
4682
ext4_handle_sync (handle );
4713
4683
4714
4684
out_handle :
4715
4685
ext4_journal_stop (handle );
4716
- out_mutex :
4686
+ out_invalidate_lock :
4687
+ filemap_invalidate_unlock (mapping );
4688
+ out :
4717
4689
inode_unlock (inode );
4718
4690
return ret ;
4719
4691
}
0 commit comments