Skip to content

Commit 93cdf49

Browse files
OjaswinMtytso
authored andcommitted
ext4: Fix best extent lstart adjustment logic in ext4_mb_new_inode_pa()
When the length of best extent found is less than the length of goal extent we need to make sure that the best extent atleast covers the start of the original request. This is done by adjusting the ac_b_ex.fe_logical (logical start) of the extent. While doing so, the current logic sometimes results in the best extent's logical range overflowing the goal extent. Since this best extent is later added to the inode preallocation list, we have a possibility of introducing overlapping preallocations. This is discussed in detail here [1]. As per Jan's suggestion, to fix this, replace the existing logic with the below logic for adjusting best extent as it keeps fragmentation in check while ensuring logical range of best extent doesn't overflow out of goal extent: 1. Check if best extent can be kept at end of goal range and still cover original start. 2. Else, check if best extent can be kept at start of goal range and still cover original start. 3. Else, keep the best extent at start of original request. Also, add a few extra BUG_ONs that might help catch errors faster. [1] https://lore.kernel.org/r/[email protected] Suggested-by: Jan Kara <[email protected]> Signed-off-by: Ojaswin Mujoo <[email protected]> Reviewed-by: Ritesh Harjani (IBM) <[email protected]> Reviewed-by: Jan Kara <[email protected]> Link: https://lore.kernel.org/r/f96aca6d415b36d1f90db86c1a8cd7e2e9d7ab0e.1679731817.git.ojaswin@linux.ibm.com Signed-off-by: Theodore Ts'o <[email protected]>
1 parent 0830344 commit 93cdf49

File tree

1 file changed

+31
-18
lines changed

1 file changed

+31
-18
lines changed

fs/ext4/mballoc.c

Lines changed: 31 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4329,6 +4329,7 @@ static void ext4_mb_use_inode_pa(struct ext4_allocation_context *ac,
43294329
BUG_ON(start < pa->pa_pstart);
43304330
BUG_ON(end > pa->pa_pstart + EXT4_C2B(sbi, pa->pa_len));
43314331
BUG_ON(pa->pa_free < len);
4332+
BUG_ON(ac->ac_b_ex.fe_len <= 0);
43324333
pa->pa_free -= len;
43334334

43344335
mb_debug(ac->ac_sb, "use %llu/%d from inode pa %p\n", start, len, pa);
@@ -4667,37 +4668,49 @@ ext4_mb_new_inode_pa(struct ext4_allocation_context *ac)
46674668
pa = ac->ac_pa;
46684669

46694670
if (ac->ac_b_ex.fe_len < ac->ac_g_ex.fe_len) {
4670-
int winl;
4671-
int wins;
4672-
int win;
4673-
int offs;
4671+
int new_bex_start;
4672+
int new_bex_end;
46744673

46754674
/* we can't allocate as much as normalizer wants.
46764675
* so, found space must get proper lstart
46774676
* to cover original request */
46784677
BUG_ON(ac->ac_g_ex.fe_logical > ac->ac_o_ex.fe_logical);
46794678
BUG_ON(ac->ac_g_ex.fe_len < ac->ac_o_ex.fe_len);
46804679

4681-
/* we're limited by original request in that
4682-
* logical block must be covered any way
4683-
* winl is window we can move our chunk within */
4684-
winl = ac->ac_o_ex.fe_logical - ac->ac_g_ex.fe_logical;
4680+
/*
4681+
* Use the below logic for adjusting best extent as it keeps
4682+
* fragmentation in check while ensuring logical range of best
4683+
* extent doesn't overflow out of goal extent:
4684+
*
4685+
* 1. Check if best ex can be kept at end of goal and still
4686+
* cover original start
4687+
* 2. Else, check if best ex can be kept at start of goal and
4688+
* still cover original start
4689+
* 3. Else, keep the best ex at start of original request.
4690+
*/
4691+
new_bex_end = ac->ac_g_ex.fe_logical +
4692+
EXT4_C2B(sbi, ac->ac_g_ex.fe_len);
4693+
new_bex_start = new_bex_end - EXT4_C2B(sbi, ac->ac_b_ex.fe_len);
4694+
if (ac->ac_o_ex.fe_logical >= new_bex_start)
4695+
goto adjust_bex;
46854696

4686-
/* also, we should cover whole original request */
4687-
wins = EXT4_C2B(sbi, ac->ac_b_ex.fe_len - ac->ac_o_ex.fe_len);
4697+
new_bex_start = ac->ac_g_ex.fe_logical;
4698+
new_bex_end =
4699+
new_bex_start + EXT4_C2B(sbi, ac->ac_b_ex.fe_len);
4700+
if (ac->ac_o_ex.fe_logical < new_bex_end)
4701+
goto adjust_bex;
46884702

4689-
/* the smallest one defines real window */
4690-
win = min(winl, wins);
4703+
new_bex_start = ac->ac_o_ex.fe_logical;
4704+
new_bex_end =
4705+
new_bex_start + EXT4_C2B(sbi, ac->ac_b_ex.fe_len);
46914706

4692-
offs = ac->ac_o_ex.fe_logical %
4693-
EXT4_C2B(sbi, ac->ac_b_ex.fe_len);
4694-
if (offs && offs < win)
4695-
win = offs;
4707+
adjust_bex:
4708+
ac->ac_b_ex.fe_logical = new_bex_start;
46964709

4697-
ac->ac_b_ex.fe_logical = ac->ac_o_ex.fe_logical -
4698-
EXT4_NUM_B2C(sbi, win);
46994710
BUG_ON(ac->ac_o_ex.fe_logical < ac->ac_b_ex.fe_logical);
47004711
BUG_ON(ac->ac_o_ex.fe_len > ac->ac_b_ex.fe_len);
4712+
BUG_ON(new_bex_end > (ac->ac_g_ex.fe_logical +
4713+
EXT4_C2B(sbi, ac->ac_g_ex.fe_len)));
47014714
}
47024715

47034716
pa->pa_lstart = ac->ac_b_ex.fe_logical;

0 commit comments

Comments
 (0)