@@ -4571,118 +4571,86 @@ static long ext4_zero_range(struct file *file, loff_t offset,
45714571 struct inode * inode = file_inode (file );
45724572 struct address_space * mapping = file -> f_mapping ;
45734573 handle_t * handle = NULL ;
4574- unsigned int max_blocks ;
45754574 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 );
45824578 unsigned int blkbits = inode -> i_blkbits ;
4579+ int ret , flags , credits ;
45834580
45844581 trace_ext4_zero_range (inode , offset , len , mode );
45854582
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-
46084583 inode_lock (inode );
46094584
46104585 /*
46114586 * Indirect files do not support unwritten extents
46124587 */
46134588 if (!(ext4_test_inode_flag (inode , EXT4_INODE_EXTENTS ))) {
46144589 ret = - EOPNOTSUPP ;
4615- goto out_mutex ;
4590+ goto out ;
46164591 }
46174592
46184593 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 ;
46224596 ret = inode_newsize_ok (inode , new_size );
46234597 if (ret )
4624- goto out_mutex ;
4598+ goto out ;
46254599 }
46264600
4627- flags = EXT4_GET_BLOCKS_CREATE_UNWRIT_EXT ;
4628-
46294601 /* Wait all existing dio workers, newcomers will block on i_rwsem */
46304602 inode_dio_wait (inode );
46314603
46324604 ret = file_modified (file );
46334605 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 ;
46454607
4646- }
4608+ /*
4609+ * Prevent page faults from reinstantiating pages we have released
4610+ * from page cache.
4611+ */
4612+ filemap_invalidate_lock (mapping );
46474613
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 ;
46524617
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 );
46584623
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+ }
46644629
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 ;
46704633
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 ;
46774638
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 );
46814648 if (ret )
4682- goto out_mutex ;
4649+ goto out_invalidate_lock ;
46834650 }
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 ;
46864654
46874655 /*
46884656 * 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,
46954663 if (IS_ERR (handle )) {
46964664 ret = PTR_ERR (handle );
46974665 ext4_std_error (inode -> i_sb , ret );
4698- goto out_mutex ;
4666+ goto out_invalidate_lock ;
46994667 }
47004668
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+
47014674 if (new_size )
47024675 ext4_update_inode_size (inode , new_size );
47034676 ret = ext4_mark_inode_dirty (handle , inode );
47044677 if (unlikely (ret ))
47054678 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 );
47104679
4680+ ext4_update_inode_fsync_trans (handle , inode , 1 );
47114681 if (file -> f_flags & O_SYNC )
47124682 ext4_handle_sync (handle );
47134683
47144684out_handle :
47154685 ext4_journal_stop (handle );
4716- out_mutex :
4686+ out_invalidate_lock :
4687+ filemap_invalidate_unlock (mapping );
4688+ out :
47174689 inode_unlock (inode );
47184690 return ret ;
47194691}
0 commit comments