Skip to content

Commit 4401e9d

Browse files
sjp38akpm00
authored andcommitted
mm/damon/core: avoid overflow in damon_feed_loop_next_input()
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>
1 parent 8e7bde6 commit 4401e9d

File tree

1 file changed

+21
-7
lines changed

1 file changed

+21
-7
lines changed

mm/damon/core.c

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1456,17 +1456,31 @@ static unsigned long damon_feed_loop_next_input(unsigned long last_input,
14561456
unsigned long score)
14571457
{
14581458
const unsigned long goal = 10000;
1459-
unsigned long score_goal_diff = max(goal, score) - min(goal, score);
1460-
unsigned long score_goal_diff_bp = score_goal_diff * 10000 / goal;
1461-
unsigned long compensation = last_input * score_goal_diff_bp / 10000;
14621459
/* Set minimum input as 10000 to avoid compensation be zero */
14631460
const unsigned long min_input = 10000;
1461+
unsigned long score_goal_diff, compensation;
1462+
bool over_achieving = score > goal;
14641463

1465-
if (goal > score)
1464+
if (score == goal)
1465+
return last_input;
1466+
if (score >= goal * 2)
1467+
return min_input;
1468+
1469+
if (over_achieving)
1470+
score_goal_diff = score - goal;
1471+
else
1472+
score_goal_diff = goal - score;
1473+
1474+
if (last_input < ULONG_MAX / score_goal_diff)
1475+
compensation = last_input * score_goal_diff / goal;
1476+
else
1477+
compensation = last_input / goal * score_goal_diff;
1478+
1479+
if (over_achieving)
1480+
return max(last_input - compensation, min_input);
1481+
if (last_input < ULONG_MAX - compensation)
14661482
return last_input + compensation;
1467-
if (last_input > compensation + min_input)
1468-
return last_input - compensation;
1469-
return min_input;
1483+
return ULONG_MAX;
14701484
}
14711485

14721486
#ifdef CONFIG_PSI

0 commit comments

Comments
 (0)