@@ -100,7 +100,7 @@ static int ext4_ext_trunc_restart_fn(struct inode *inode, int *dropped)
100100 * i_rwsem. So we can safely drop the i_data_sem here.
101101 */
102102 BUG_ON (EXT4_JOURNAL (inode ) == NULL );
103- ext4_discard_preallocations (inode , 0 );
103+ ext4_discard_preallocations (inode );
104104 up_write (& EXT4_I (inode )-> i_data_sem );
105105 * dropped = 1 ;
106106 return 0 ;
@@ -2229,7 +2229,7 @@ static int ext4_fill_es_cache_info(struct inode *inode,
22292229
22302230
22312231/*
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
22332233 * @inode: inode we lookup in
22342234 * @path: path in extent tree to @lblk
22352235 * @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,
22412241 * The function returns the length of a hole starting at @lblk. We update @lblk
22422242 * to the beginning of the hole if we managed to find it.
22432243 */
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 )
22472247{
22482248 int depth = ext_depth (inode );
22492249 struct ext4_extent * ex ;
@@ -2270,30 +2270,6 @@ static ext4_lblk_t ext4_ext_determine_hole(struct inode *inode,
22702270 return len ;
22712271}
22722272
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-
22972273/*
22982274 * ext4_ext_rm_idx:
22992275 * removes index from the index block.
@@ -4062,6 +4038,72 @@ static int get_implied_cluster_alloc(struct super_block *sb,
40624038 return 0 ;
40634039}
40644040
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+ }
40654107
40664108/*
40674109 * Block allocation/map/preallocation routine for extents based files
@@ -4179,22 +4221,12 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
41794221 * we couldn't try to create block if create flag is zero
41804222 */
41814223 if ((flags & EXT4_GET_BLOCKS_CREATE ) == 0 ) {
4182- ext4_lblk_t hole_start , hole_len ;
4224+ ext4_lblk_t len ;
41834225
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 );
41914227
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 ;
41954228 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 );
41984230 goto out ;
41994231 }
42004232
@@ -4313,7 +4345,7 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
43134345 * not a good idea to call discard here directly,
43144346 * but otherwise we'd need to call it every free().
43154347 */
4316- ext4_discard_preallocations (inode , 0 );
4348+ ext4_discard_preallocations (inode );
43174349 if (flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE )
43184350 fb_flags = EXT4_FREE_BLOCKS_NO_QUOT_UPDATE ;
43194351 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)
53575389 ext4_fc_mark_ineligible (sb , EXT4_FC_REASON_FALLOC_RANGE , handle );
53585390
53595391 down_write (& EXT4_I (inode )-> i_data_sem );
5360- ext4_discard_preallocations (inode , 0 );
5392+ ext4_discard_preallocations (inode );
53615393 ext4_es_remove_extent (inode , punch_start , EXT_MAX_BLOCKS - punch_start );
53625394
53635395 ret = ext4_ext_remove_space (inode , punch_start , punch_stop - 1 );
53645396 if (ret ) {
53655397 up_write (& EXT4_I (inode )-> i_data_sem );
53665398 goto out_stop ;
53675399 }
5368- ext4_discard_preallocations (inode , 0 );
5400+ ext4_discard_preallocations (inode );
53695401
53705402 ret = ext4_ext_shift_extents (inode , handle , punch_stop ,
53715403 punch_stop - punch_start , SHIFT_LEFT );
@@ -5497,7 +5529,7 @@ static int ext4_insert_range(struct file *file, loff_t offset, loff_t len)
54975529 goto out_stop ;
54985530
54995531 down_write (& EXT4_I (inode )-> i_data_sem );
5500- ext4_discard_preallocations (inode , 0 );
5532+ ext4_discard_preallocations (inode );
55015533
55025534 path = ext4_find_extent (inode , offset_lblk , NULL , 0 );
55035535 if (IS_ERR (path )) {
0 commit comments