@@ -3991,58 +3991,49 @@ int ext4_punch_hole(struct file *file, loff_t offset, loff_t length)
39913991{
39923992 struct inode * inode = file_inode (file );
39933993 struct super_block * sb = inode -> i_sb ;
3994- ext4_lblk_t first_block , stop_block ;
3994+ ext4_lblk_t start_lblk , end_lblk ;
39953995 struct address_space * mapping = inode -> i_mapping ;
3996- loff_t first_block_offset , last_block_offset , max_length ;
3997- struct ext4_sb_info * sbi = EXT4_SB ( inode -> i_sb ) ;
3996+ loff_t max_end = EXT4_SB ( sb ) -> s_bitmap_maxbytes - sb -> s_blocksize ;
3997+ loff_t end = offset + length ;
39983998 handle_t * handle ;
39993999 unsigned int credits ;
4000- int ret = 0 , ret2 = 0 ;
4000+ int ret = 0 ;
40014001
40024002 trace_ext4_punch_hole (inode , offset , length , 0 );
40034003
40044004 inode_lock (inode );
40054005
40064006 /* No need to punch hole beyond i_size */
40074007 if (offset >= inode -> i_size )
4008- goto out_mutex ;
4008+ goto out ;
40094009
40104010 /*
4011- * If the hole extends beyond i_size, set the hole
4012- * to end after the page that contains i_size
4011+ * If the hole extends beyond i_size, set the hole to end after
4012+ * the page that contains i_size, and also make sure that the hole
4013+ * within one block before last range.
40134014 */
4014- if (offset + length > inode -> i_size ) {
4015- length = inode -> i_size +
4016- PAGE_SIZE - ( inode -> i_size & ( PAGE_SIZE - 1 )) -
4017- offset ;
4018- }
4015+ if (end > inode -> i_size )
4016+ end = round_up ( inode -> i_size , PAGE_SIZE );
4017+ if ( end > max_end )
4018+ end = max_end ;
4019+ length = end - offset ;
40194020
40204021 /*
4021- * For punch hole the length + offset needs to be within one block
4022- * before last range. Adjust the length if it goes beyond that limit .
4022+ * Attach jinode to inode for jbd2 if we do any zeroing of partial
4023+ * block .
40234024 */
4024- max_length = sbi -> s_bitmap_maxbytes - inode -> i_sb -> s_blocksize ;
4025- if (offset + length > max_length )
4026- length = max_length - offset ;
4027-
4028- if (offset & (sb -> s_blocksize - 1 ) ||
4029- (offset + length ) & (sb -> s_blocksize - 1 )) {
4030- /*
4031- * Attach jinode to inode for jbd2 if we do any zeroing of
4032- * partial block
4033- */
4025+ if (!IS_ALIGNED (offset | end , sb -> s_blocksize )) {
40344026 ret = ext4_inode_attach_jinode (inode );
40354027 if (ret < 0 )
4036- goto out_mutex ;
4037-
4028+ goto out ;
40384029 }
40394030
40404031 /* Wait all existing dio workers, newcomers will block on i_rwsem */
40414032 inode_dio_wait (inode );
40424033
40434034 ret = file_modified (file );
40444035 if (ret )
4045- goto out_mutex ;
4036+ goto out ;
40464037
40474038 /*
40484039 * Prevent page faults from reinstantiating pages we have released from
@@ -4052,22 +4043,16 @@ int ext4_punch_hole(struct file *file, loff_t offset, loff_t length)
40524043
40534044 ret = ext4_break_layouts (inode );
40544045 if (ret )
4055- goto out_dio ;
4046+ goto out_invalidate_lock ;
40564047
4057- first_block_offset = round_up (offset , sb -> s_blocksize );
4058- last_block_offset = round_down ((offset + length ), sb -> s_blocksize ) - 1 ;
4048+ ret = ext4_update_disksize_before_punch (inode , offset , length );
4049+ if (ret )
4050+ goto out_invalidate_lock ;
40594051
40604052 /* Now release the pages and zero block aligned part of pages*/
4061- if (last_block_offset > first_block_offset ) {
4062- ret = ext4_update_disksize_before_punch (inode , offset , length );
4063- if (ret )
4064- goto out_dio ;
4065-
4066- ret = ext4_truncate_page_cache_block_range (inode ,
4067- first_block_offset , last_block_offset + 1 );
4068- if (ret )
4069- goto out_dio ;
4070- }
4053+ ret = ext4_truncate_page_cache_block_range (inode , offset , end );
4054+ if (ret )
4055+ goto out_invalidate_lock ;
40714056
40724057 if (ext4_test_inode_flag (inode , EXT4_INODE_EXTENTS ))
40734058 credits = ext4_writepage_trans_blocks (inode );
@@ -4077,52 +4062,54 @@ int ext4_punch_hole(struct file *file, loff_t offset, loff_t length)
40774062 if (IS_ERR (handle )) {
40784063 ret = PTR_ERR (handle );
40794064 ext4_std_error (sb , ret );
4080- goto out_dio ;
4065+ goto out_invalidate_lock ;
40814066 }
40824067
4083- ret = ext4_zero_partial_blocks (handle , inode , offset ,
4084- length );
4068+ ret = ext4_zero_partial_blocks (handle , inode , offset , length );
40854069 if (ret )
4086- goto out_stop ;
4087-
4088- first_block = (offset + sb -> s_blocksize - 1 ) >>
4089- EXT4_BLOCK_SIZE_BITS (sb );
4090- stop_block = (offset + length ) >> EXT4_BLOCK_SIZE_BITS (sb );
4070+ goto out_handle ;
40914071
40924072 /* If there are blocks to remove, do it */
4093- if (stop_block > first_block ) {
4094- ext4_lblk_t hole_len = stop_block - first_block ;
4073+ start_lblk = EXT4_B_TO_LBLK (inode , offset );
4074+ end_lblk = end >> inode -> i_blkbits ;
4075+
4076+ if (end_lblk > start_lblk ) {
4077+ ext4_lblk_t hole_len = end_lblk - start_lblk ;
40954078
40964079 down_write (& EXT4_I (inode )-> i_data_sem );
40974080 ext4_discard_preallocations (inode );
40984081
4099- ext4_es_remove_extent (inode , first_block , hole_len );
4082+ ext4_es_remove_extent (inode , start_lblk , hole_len );
41004083
41014084 if (ext4_test_inode_flag (inode , EXT4_INODE_EXTENTS ))
4102- ret = ext4_ext_remove_space (inode , first_block ,
4103- stop_block - 1 );
4085+ ret = ext4_ext_remove_space (inode , start_lblk ,
4086+ end_lblk - 1 );
41044087 else
4105- ret = ext4_ind_remove_space (handle , inode , first_block ,
4106- stop_block );
4088+ ret = ext4_ind_remove_space (handle , inode , start_lblk ,
4089+ end_lblk );
4090+ if (ret ) {
4091+ up_write (& EXT4_I (inode )-> i_data_sem );
4092+ goto out_handle ;
4093+ }
41074094
4108- ext4_es_insert_extent (inode , first_block , hole_len , ~0 ,
4095+ ext4_es_insert_extent (inode , start_lblk , hole_len , ~0 ,
41094096 EXTENT_STATUS_HOLE , 0 );
41104097 up_write (& EXT4_I (inode )-> i_data_sem );
41114098 }
4112- ext4_fc_track_range (handle , inode , first_block , stop_block );
4099+ ext4_fc_track_range (handle , inode , start_lblk , end_lblk );
4100+
4101+ ret = ext4_mark_inode_dirty (handle , inode );
4102+ if (unlikely (ret ))
4103+ goto out_handle ;
4104+
4105+ ext4_update_inode_fsync_trans (handle , inode , 1 );
41134106 if (IS_SYNC (inode ))
41144107 ext4_handle_sync (handle );
4115-
4116- ret2 = ext4_mark_inode_dirty (handle , inode );
4117- if (unlikely (ret2 ))
4118- ret = ret2 ;
4119- if (ret >= 0 )
4120- ext4_update_inode_fsync_trans (handle , inode , 1 );
4121- out_stop :
4108+ out_handle :
41224109 ext4_journal_stop (handle );
4123- out_dio :
4110+ out_invalidate_lock :
41244111 filemap_invalidate_unlock (mapping );
4125- out_mutex :
4112+ out :
41264113 inode_unlock (inode );
41274114 return ret ;
41284115}
0 commit comments