mm/damon/core: use abs_diff() instead of abs()

Use of abs() in damon_merge_regions_of() could cause a silent integer
overflow since the macro casts unsigned int to signed int.  It is unlikely
to have such a large value for nr_accesses.  Even though it happens, the
user impact is just degraded monitoring results.  Users showing bad
monitoring results for weird setup is quite trivial.  But the code is
obviously wrong.  Use abs_diff() instead.

The issue was discovered [1] by Sashiko.

Link: https://lore.kernel.org/20260710134651.18084-8-sj@kernel.org
Link: https://lore.kernel.org/20260705213817.100841-1-sj@kernel.org/ [1]
Signed-off-by: SJ Park <sj@kernel.org>
Cc: David Hildenbrand <david@kernel.org>
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: Liam R. Howlett <liam@infradead.org>
Cc: Lorenzo Stoakes <ljs@kernel.org>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Mike Rapoport <rppt@kernel.org>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Vlastimil Babka <vbabka@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
This commit is contained in:
SJ Park 2026-07-10 06:46:36 -07:00 committed by Andrew Morton
parent 3858025f48
commit e1f150d415

View File

@ -3261,7 +3261,7 @@ static void damon_merge_regions_of(struct damon_target *t, unsigned int thres,
struct damon_region *r, *prev = NULL, *next;
damon_for_each_region_safe(r, next, t) {
if (abs(r->nr_accesses - r->last_nr_accesses) > thres)
if (abs_diff(r->nr_accesses, r->last_nr_accesses) > thres)
r->age = 0;
else if ((r->nr_accesses == 0) != (r->last_nr_accesses == 0))
r->age = 0;
@ -3269,7 +3269,7 @@ static void damon_merge_regions_of(struct damon_target *t, unsigned int thres,
r->age++;
if (prev && prev->ar.end == r->ar.start &&
abs(prev->nr_accesses - r->nr_accesses) <= thres &&
abs_diff(prev->nr_accesses, r->nr_accesses) <= thres &&
damon_sz_region(prev) + damon_sz_region(r) <= sz_limit)
damon_merge_two_regions(t, prev, r);
else