@@ -100,7 +100,7 @@ static int ext4_ext_trunc_restart_fn(struct inode *inode, int *dropped)
100
100
* i_rwsem. So we can safely drop the i_data_sem here.
101
101
*/
102
102
BUG_ON (EXT4_JOURNAL (inode ) == NULL );
103
- ext4_discard_preallocations (inode , 0 );
103
+ ext4_discard_preallocations (inode );
104
104
up_write (& EXT4_I (inode )-> i_data_sem );
105
105
* dropped = 1 ;
106
106
return 0 ;
@@ -2229,7 +2229,7 @@ static int ext4_fill_es_cache_info(struct inode *inode,
2229
2229
2230
2230
2231
2231
/*
2232
- * ext4_ext_determine_hole - determine hole around given block
2232
+ * ext4_ext_find_hole - find hole around given block according to the given path
2233
2233
* @inode: inode we lookup in
2234
2234
* @path: path in extent tree to @lblk
2235
2235
* @lblk: pointer to logical block around which we want to determine hole
@@ -2241,9 +2241,9 @@ static int ext4_fill_es_cache_info(struct inode *inode,
2241
2241
* The function returns the length of a hole starting at @lblk. We update @lblk
2242
2242
* to the beginning of the hole if we managed to find it.
2243
2243
*/
2244
- static ext4_lblk_t ext4_ext_determine_hole (struct inode * inode ,
2245
- struct ext4_ext_path * path ,
2246
- ext4_lblk_t * lblk )
2244
+ static ext4_lblk_t ext4_ext_find_hole (struct inode * inode ,
2245
+ struct ext4_ext_path * path ,
2246
+ ext4_lblk_t * lblk )
2247
2247
{
2248
2248
int depth = ext_depth (inode );
2249
2249
struct ext4_extent * ex ;
@@ -2270,30 +2270,6 @@ static ext4_lblk_t ext4_ext_determine_hole(struct inode *inode,
2270
2270
return len ;
2271
2271
}
2272
2272
2273
- /*
2274
- * ext4_ext_put_gap_in_cache:
2275
- * calculate boundaries of the gap that the requested block fits into
2276
- * and cache this gap
2277
- */
2278
- static void
2279
- ext4_ext_put_gap_in_cache (struct inode * inode , ext4_lblk_t hole_start ,
2280
- ext4_lblk_t hole_len )
2281
- {
2282
- struct extent_status es ;
2283
-
2284
- ext4_es_find_extent_range (inode , & ext4_es_is_delayed , hole_start ,
2285
- hole_start + hole_len - 1 , & es );
2286
- if (es .es_len ) {
2287
- /* There's delayed extent containing lblock? */
2288
- if (es .es_lblk <= hole_start )
2289
- return ;
2290
- hole_len = min (es .es_lblk - hole_start , hole_len );
2291
- }
2292
- ext_debug (inode , " -> %u:%u\n" , hole_start , hole_len );
2293
- ext4_es_insert_extent (inode , hole_start , hole_len , ~0 ,
2294
- EXTENT_STATUS_HOLE );
2295
- }
2296
-
2297
2273
/*
2298
2274
* ext4_ext_rm_idx:
2299
2275
* removes index from the index block.
@@ -4062,6 +4038,72 @@ static int get_implied_cluster_alloc(struct super_block *sb,
4062
4038
return 0 ;
4063
4039
}
4064
4040
4041
+ /*
4042
+ * Determine hole length around the given logical block, first try to
4043
+ * locate and expand the hole from the given @path, and then adjust it
4044
+ * if it's partially or completely converted to delayed extents, insert
4045
+ * it into the extent cache tree if it's indeed a hole, finally return
4046
+ * the length of the determined extent.
4047
+ */
4048
+ static ext4_lblk_t ext4_ext_determine_insert_hole (struct inode * inode ,
4049
+ struct ext4_ext_path * path ,
4050
+ ext4_lblk_t lblk )
4051
+ {
4052
+ ext4_lblk_t hole_start , len ;
4053
+ struct extent_status es ;
4054
+
4055
+ hole_start = lblk ;
4056
+ len = ext4_ext_find_hole (inode , path , & hole_start );
4057
+ again :
4058
+ ext4_es_find_extent_range (inode , & ext4_es_is_delayed , hole_start ,
4059
+ hole_start + len - 1 , & es );
4060
+ if (!es .es_len )
4061
+ goto insert_hole ;
4062
+
4063
+ /*
4064
+ * There's a delalloc extent in the hole, handle it if the delalloc
4065
+ * extent is in front of, behind and straddle the queried range.
4066
+ */
4067
+ if (lblk >= es .es_lblk + es .es_len ) {
4068
+ /*
4069
+ * The delalloc extent is in front of the queried range,
4070
+ * find again from the queried start block.
4071
+ */
4072
+ len -= lblk - hole_start ;
4073
+ hole_start = lblk ;
4074
+ goto again ;
4075
+ } else if (in_range (lblk , es .es_lblk , es .es_len )) {
4076
+ /*
4077
+ * The delalloc extent containing lblk, it must have been
4078
+ * added after ext4_map_blocks() checked the extent status
4079
+ * tree so we are not holding i_rwsem and delalloc info is
4080
+ * only stabilized by i_data_sem we are going to release
4081
+ * soon. Don't modify the extent status tree and report
4082
+ * extent as a hole, just adjust the length to the delalloc
4083
+ * extent's after lblk.
4084
+ */
4085
+ len = es .es_lblk + es .es_len - lblk ;
4086
+ return len ;
4087
+ } else {
4088
+ /*
4089
+ * The delalloc extent is partially or completely behind
4090
+ * the queried range, update hole length until the
4091
+ * beginning of the delalloc extent.
4092
+ */
4093
+ len = min (es .es_lblk - hole_start , len );
4094
+ }
4095
+
4096
+ insert_hole :
4097
+ /* Put just found gap into cache to speed up subsequent requests */
4098
+ ext_debug (inode , " -> %u:%u\n" , hole_start , len );
4099
+ ext4_es_insert_extent (inode , hole_start , len , ~0 , EXTENT_STATUS_HOLE );
4100
+
4101
+ /* Update hole_len to reflect hole size after lblk */
4102
+ if (hole_start != lblk )
4103
+ len -= lblk - hole_start ;
4104
+
4105
+ return len ;
4106
+ }
4065
4107
4066
4108
/*
4067
4109
* Block allocation/map/preallocation routine for extents based files
@@ -4179,22 +4221,12 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
4179
4221
* we couldn't try to create block if create flag is zero
4180
4222
*/
4181
4223
if ((flags & EXT4_GET_BLOCKS_CREATE ) == 0 ) {
4182
- ext4_lblk_t hole_start , hole_len ;
4224
+ ext4_lblk_t len ;
4183
4225
4184
- hole_start = map -> m_lblk ;
4185
- hole_len = ext4_ext_determine_hole (inode , path , & hole_start );
4186
- /*
4187
- * put just found gap into cache to speed up
4188
- * subsequent requests
4189
- */
4190
- ext4_ext_put_gap_in_cache (inode , hole_start , hole_len );
4226
+ len = ext4_ext_determine_insert_hole (inode , path , map -> m_lblk );
4191
4227
4192
- /* Update hole_len to reflect hole size after map->m_lblk */
4193
- if (hole_start != map -> m_lblk )
4194
- hole_len -= map -> m_lblk - hole_start ;
4195
4228
map -> m_pblk = 0 ;
4196
- map -> m_len = min_t (unsigned int , map -> m_len , hole_len );
4197
-
4229
+ map -> m_len = min_t (unsigned int , map -> m_len , len );
4198
4230
goto out ;
4199
4231
}
4200
4232
@@ -4313,7 +4345,7 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
4313
4345
* not a good idea to call discard here directly,
4314
4346
* but otherwise we'd need to call it every free().
4315
4347
*/
4316
- ext4_discard_preallocations (inode , 0 );
4348
+ ext4_discard_preallocations (inode );
4317
4349
if (flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE )
4318
4350
fb_flags = EXT4_FREE_BLOCKS_NO_QUOT_UPDATE ;
4319
4351
ext4_free_blocks (handle , inode , NULL , newblock ,
@@ -5357,15 +5389,15 @@ static int ext4_collapse_range(struct file *file, loff_t offset, loff_t len)
5357
5389
ext4_fc_mark_ineligible (sb , EXT4_FC_REASON_FALLOC_RANGE , handle );
5358
5390
5359
5391
down_write (& EXT4_I (inode )-> i_data_sem );
5360
- ext4_discard_preallocations (inode , 0 );
5392
+ ext4_discard_preallocations (inode );
5361
5393
ext4_es_remove_extent (inode , punch_start , EXT_MAX_BLOCKS - punch_start );
5362
5394
5363
5395
ret = ext4_ext_remove_space (inode , punch_start , punch_stop - 1 );
5364
5396
if (ret ) {
5365
5397
up_write (& EXT4_I (inode )-> i_data_sem );
5366
5398
goto out_stop ;
5367
5399
}
5368
- ext4_discard_preallocations (inode , 0 );
5400
+ ext4_discard_preallocations (inode );
5369
5401
5370
5402
ret = ext4_ext_shift_extents (inode , handle , punch_stop ,
5371
5403
punch_stop - punch_start , SHIFT_LEFT );
@@ -5497,7 +5529,7 @@ static int ext4_insert_range(struct file *file, loff_t offset, loff_t len)
5497
5529
goto out_stop ;
5498
5530
5499
5531
down_write (& EXT4_I (inode )-> i_data_sem );
5500
- ext4_discard_preallocations (inode , 0 );
5532
+ ext4_discard_preallocations (inode );
5501
5533
5502
5534
path = ext4_find_extent (inode , offset_lblk , NULL , 0 );
5503
5535
if (IS_ERR (path )) {
0 commit comments