mm/damon/sysfs: use dynamically allocated repeat mode damon_call_control
authorSeongJae Park <sj@kernel.org>
Mon, 8 Sep 2025 20:15:13 +0000 (13:15 -0700)
committerAndrew Morton <akpm@linux-foundation.org>
Sat, 13 Sep 2025 20:05:36 +0000 (13:05 -0700)
DAMON sysfs interface is using a single global repeat mode
damon_call_control variable for refresh_ms handling, for all DAMON
contexts.  As a result, when there are more than one context, the single
global damon_call_control is unexpectedly over-written (corrupted).
Particularly the ->link field is overwritten by the multiple contexts and
this can cause a user hangup, and/or a kernel crash.  Fix it by using
dynamically allocated damon_call_control object per DAMON context.

Link: https://lkml.kernel.org/r/20250908201513.60802-3-sj@kernel.org
Link: https://lore.kernel.org/20250904011738.930-1-yunjeong.mun@sk.com
Link: https://lore.kernel.org/20250905035411.39501-1-sj@kernel.org
Fixes: d809a7c64ba8 ("mm/damon/sysfs: implement refresh_ms file internal work")
Signed-off-by: SeongJae Park <sj@kernel.org>
Reported-by: Yunjeong Mun <yunjeong.mun@sk.com>
Closes: https://lore.kernel.org/20250904011738.930-1-yunjeong.mun@sk.com
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
mm/damon/sysfs.c

index 7b9254cadd5f878460d0252651c903d060564a2c..c96c2154128faadf58f25813b1777f56b536825b 100644 (file)
@@ -1534,14 +1534,10 @@ static int damon_sysfs_repeat_call_fn(void *data)
        return 0;
 }
 
-static struct damon_call_control damon_sysfs_repeat_call_control = {
-       .fn = damon_sysfs_repeat_call_fn,
-       .repeat = true,
-};
-
 static int damon_sysfs_turn_damon_on(struct damon_sysfs_kdamond *kdamond)
 {
        struct damon_ctx *ctx;
+       struct damon_call_control *repeat_call_control;
        int err;
 
        if (damon_sysfs_kdamond_running(kdamond))
@@ -1554,18 +1550,29 @@ static int damon_sysfs_turn_damon_on(struct damon_sysfs_kdamond *kdamond)
                damon_destroy_ctx(kdamond->damon_ctx);
        kdamond->damon_ctx = NULL;
 
+       repeat_call_control = kmalloc(sizeof(*repeat_call_control),
+                       GFP_KERNEL);
+       if (!repeat_call_control)
+               return -ENOMEM;
+
        ctx = damon_sysfs_build_ctx(kdamond->contexts->contexts_arr[0]);
-       if (IS_ERR(ctx))
+       if (IS_ERR(ctx)) {
+               kfree(repeat_call_control);
                return PTR_ERR(ctx);
+       }
        err = damon_start(&ctx, 1, false);
        if (err) {
+               kfree(repeat_call_control);
                damon_destroy_ctx(ctx);
                return err;
        }
        kdamond->damon_ctx = ctx;
 
-       damon_sysfs_repeat_call_control.data = kdamond;
-       damon_call(ctx, &damon_sysfs_repeat_call_control);
+       repeat_call_control->fn = damon_sysfs_repeat_call_fn;
+       repeat_call_control->data = kdamond;
+       repeat_call_control->repeat = true;
+       repeat_call_control->dealloc_on_cancel = true;
+       damon_call(ctx, repeat_call_control);
        return err;
 }