]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
mm/damon/core: support addr_unit on damon_find_biggest_system_ram()
authorSeongJae Park <sj@kernel.org>
Wed, 11 Mar 2026 05:29:23 +0000 (22:29 -0700)
committerAndrew Morton <akpm@linux-foundation.org>
Sun, 5 Apr 2026 20:53:28 +0000 (13:53 -0700)
damon_find_biggest_system_ram() sets an 'unsigned long' variable with
'resource_size_t' value.  This is fundamentally wrong.  On environments
such as ARM 32 bit machines having LPAE (Large Physical Address
Extensions), which DAMON supports, the size of 'unsigned long' may be
smaller than that of 'resource_size_t'.  It is safe, though, since we
restrict the walk to be done only up to ULONG_MAX.

DAMON supports the address size gap using 'addr_unit'.  We didn't add the
support to the function, just to make the initial support change small.
Now the support is reasonably settled.  This kind of gap is only making
the code inconsistent and easy to be confused.  Add the support of
'addr_unit' to the function, by letting callers pass the 'addr_unit' and
handling it in the function.  All callers are passing 'addr_unit' 1,
though, to keep the old behavior.

[sj@kernel.org: verify found biggest system ram]
Link: https://lkml.kernel.org/r/20260317144725.88524-1-sj@kernel.org
Link: https://lkml.kernel.org/r/20260311052927.93921-3-sj@kernel.org
Signed-off-by: SeongJae Park <sj@kernel.org>
Cc: Yang yingliang <yangyingliang@huawei.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
mm/damon/core.c

index ce791b544b5dedb939c234be2d2ceefb45a5ae2b..f5f46ba5d537c394431d902a7215cfeb3f5996be 100644 (file)
@@ -3064,31 +3064,43 @@ done:
 
 static int walk_system_ram(struct resource *res, void *arg)
 {
-       struct damon_addr_range *a = arg;
+       struct resource *a = arg;
 
-       if (a->end - a->start < resource_size(res)) {
+       if (resource_size(a) < resource_size(res)) {
                a->start = res->start;
-               a->end = res->end + 1;
+               a->end = res->end;
        }
        return 0;
 }
 
+static unsigned long damon_res_to_core_addr(resource_size_t ra,
+               unsigned long addr_unit)
+{
+       /*
+        * Use div_u64() for avoiding linking errors related with __udivdi3,
+        * __aeabi_uldivmod, or similar problems.  This should also improve the
+        * performance optimization (read div_u64() comment for the detail).
+        */
+       if (sizeof(ra) == 8 && sizeof(addr_unit) == 4)
+               return div_u64(ra, addr_unit);
+       return ra / addr_unit;
+}
+
 /*
  * Find biggest 'System RAM' resource and store its start and end address in
  * @start and @end, respectively.  If no System RAM is found, returns false.
  */
 static bool damon_find_biggest_system_ram(unsigned long *start,
-                                               unsigned long *end)
+               unsigned long *end, unsigned long addr_unit)
 
 {
-       struct damon_addr_range arg = {};
+       struct resource res = {};
 
-       walk_system_ram_res(0, ULONG_MAX, &arg, walk_system_ram);
-       if (arg.end <= arg.start)
+       walk_system_ram_res(0, -1, &res, walk_system_ram);
+       *start = damon_res_to_core_addr(res.start, addr_unit);
+       *end = damon_res_to_core_addr(res.end + 1, addr_unit);
+       if (*end <= *start)
                return false;
-
-       *start = arg.start;
-       *end = arg.end;
        return true;
 }
 
@@ -3118,7 +3130,7 @@ int damon_set_region_biggest_system_ram_default(struct damon_target *t,
                return -EINVAL;
 
        if (!*start && !*end &&
-               !damon_find_biggest_system_ram(start, end))
+               !damon_find_biggest_system_ram(start, end, 1))
                return -EINVAL;
 
        addr_range.start = *start;