@@ -3991,58 +3991,49 @@ int ext4_punch_hole(struct file *file, loff_t offset, loff_t length)
3991
3991
{
3992
3992
struct inode * inode = file_inode (file );
3993
3993
struct super_block * sb = inode -> i_sb ;
3994
- ext4_lblk_t first_block , stop_block ;
3994
+ ext4_lblk_t start_lblk , end_lblk ;
3995
3995
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 ;
3998
3998
handle_t * handle ;
3999
3999
unsigned int credits ;
4000
- int ret = 0 , ret2 = 0 ;
4000
+ int ret = 0 ;
4001
4001
4002
4002
trace_ext4_punch_hole (inode , offset , length , 0 );
4003
4003
4004
4004
inode_lock (inode );
4005
4005
4006
4006
/* No need to punch hole beyond i_size */
4007
4007
if (offset >= inode -> i_size )
4008
- goto out_mutex ;
4008
+ goto out ;
4009
4009
4010
4010
/*
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.
4013
4014
*/
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 ;
4019
4020
4020
4021
/*
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 .
4023
4024
*/
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 )) {
4034
4026
ret = ext4_inode_attach_jinode (inode );
4035
4027
if (ret < 0 )
4036
- goto out_mutex ;
4037
-
4028
+ goto out ;
4038
4029
}
4039
4030
4040
4031
/* Wait all existing dio workers, newcomers will block on i_rwsem */
4041
4032
inode_dio_wait (inode );
4042
4033
4043
4034
ret = file_modified (file );
4044
4035
if (ret )
4045
- goto out_mutex ;
4036
+ goto out ;
4046
4037
4047
4038
/*
4048
4039
* 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)
4052
4043
4053
4044
ret = ext4_break_layouts (inode );
4054
4045
if (ret )
4055
- goto out_dio ;
4046
+ goto out_invalidate_lock ;
4056
4047
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 ;
4059
4051
4060
4052
/* 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 ;
4071
4056
4072
4057
if (ext4_test_inode_flag (inode , EXT4_INODE_EXTENTS ))
4073
4058
credits = ext4_writepage_trans_blocks (inode );
@@ -4077,52 +4062,54 @@ int ext4_punch_hole(struct file *file, loff_t offset, loff_t length)
4077
4062
if (IS_ERR (handle )) {
4078
4063
ret = PTR_ERR (handle );
4079
4064
ext4_std_error (sb , ret );
4080
- goto out_dio ;
4065
+ goto out_invalidate_lock ;
4081
4066
}
4082
4067
4083
- ret = ext4_zero_partial_blocks (handle , inode , offset ,
4084
- length );
4068
+ ret = ext4_zero_partial_blocks (handle , inode , offset , length );
4085
4069
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 ;
4091
4071
4092
4072
/* 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 ;
4095
4078
4096
4079
down_write (& EXT4_I (inode )-> i_data_sem );
4097
4080
ext4_discard_preallocations (inode );
4098
4081
4099
- ext4_es_remove_extent (inode , first_block , hole_len );
4082
+ ext4_es_remove_extent (inode , start_lblk , hole_len );
4100
4083
4101
4084
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 );
4104
4087
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
+ }
4107
4094
4108
- ext4_es_insert_extent (inode , first_block , hole_len , ~0 ,
4095
+ ext4_es_insert_extent (inode , start_lblk , hole_len , ~0 ,
4109
4096
EXTENT_STATUS_HOLE , 0 );
4110
4097
up_write (& EXT4_I (inode )-> i_data_sem );
4111
4098
}
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 );
4113
4106
if (IS_SYNC (inode ))
4114
4107
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 :
4122
4109
ext4_journal_stop (handle );
4123
- out_dio :
4110
+ out_invalidate_lock :
4124
4111
filemap_invalidate_unlock (mapping );
4125
- out_mutex :
4112
+ out :
4126
4113
inode_unlock (inode );
4127
4114
return ret ;
4128
4115
}
0 commit comments