Skip to content

Commit 2d339a1

Browse files
sjp38gregkh
authored andcommitted
mm/damon/core: avoid overflow in damon_feed_loop_next_input()
commit 4401e9d upstream. damon_feed_loop_next_input() is inefficient and fragile to overflows. Specifically, 'score_goal_diff_bp' calculation can overflow when 'score' is high. The calculation is actually unnecessary at all because 'goal' is a constant of value 10,000. Calculation of 'compensation' is again fragile to overflow. Final calculation of return value for under-achiving case is again fragile to overflow when the current score is under-achieving the target. Add two corner cases handling at the beginning of the function to make the body easier to read, and rewrite the body of the function to avoid overflows and the unnecessary bp value calcuation. Link: https://lkml.kernel.org/r/20241031161203.47751-1-sj@kernel.org Fixes: 9294a03 ("mm/damon/core: implement goal-oriented feedback-driven quota auto-tuning") Signed-off-by: SeongJae Park <sj@kernel.org> Reported-by: Guenter Roeck <linux@roeck-us.net> Closes: https://lore.kernel.org/944f3d5b-9177-48e7-8ec9-7f1331a3fea3@roeck-us.net Tested-by: Guenter Roeck <linux@roeck-us.net> Cc: <stable@vger.kernel.org> [6.8.x] Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 0208ea1 commit 2d339a1

1 file changed

Lines changed: 21 additions & 7 deletions

File tree

mm/damon/core.c

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1450,17 +1450,31 @@ static unsigned long damon_feed_loop_next_input(unsigned long last_input,
14501450
unsigned long score)
14511451
{
14521452
const unsigned long goal = 10000;
1453-
unsigned long score_goal_diff = max(goal, score) - min(goal, score);
1454-
unsigned long score_goal_diff_bp = score_goal_diff * 10000 / goal;
1455-
unsigned long compensation = last_input * score_goal_diff_bp / 10000;
14561453
/* Set minimum input as 10000 to avoid compensation be zero */
14571454
const unsigned long min_input = 10000;
1455+
unsigned long score_goal_diff, compensation;
1456+
bool over_achieving = score > goal;
14581457

1459-
if (goal > score)
1458+
if (score == goal)
1459+
return last_input;
1460+
if (score >= goal * 2)
1461+
return min_input;
1462+
1463+
if (over_achieving)
1464+
score_goal_diff = score - goal;
1465+
else
1466+
score_goal_diff = goal - score;
1467+
1468+
if (last_input < ULONG_MAX / score_goal_diff)
1469+
compensation = last_input * score_goal_diff / goal;
1470+
else
1471+
compensation = last_input / goal * score_goal_diff;
1472+
1473+
if (over_achieving)
1474+
return max(last_input - compensation, min_input);
1475+
if (last_input < ULONG_MAX - compensation)
14601476
return last_input + compensation;
1461-
if (last_input > compensation + min_input)
1462-
return last_input - compensation;
1463-
return min_input;
1477+
return ULONG_MAX;
14641478
}
14651479

14661480
#ifdef CONFIG_PSI

0 commit comments

Comments
 (0)