Commit 04a06b13 authored by SeongJae Park's avatar SeongJae Park Committed by Andrew Morton
Browse files

mm/damon/sysfs: use dynamically allocated repeat mode damon_call_control

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 [1]
Link: https://lore.kernel.org/20250905035411.39501-1-sj@kernel.org

 [2]
Fixes: d809a7c6 ("mm/damon/sysfs: implement refresh_ms file internal work")
Signed-off-by: default avatarSeongJae Park <sj@kernel.org>
Reported-by: default avatarYunjeong Mun <yunjeong.mun@sk.com>
Closes: https://lore.kernel.org/20250904011738.930-1-yunjeong.mun@sk.com


Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
parent e6a0deb6
Loading
Loading
Loading
Loading
+15 −8
Original line number Diff line number Diff line
@@ -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;
}