From e4742be45ea45bf554399ce89a09f71e525d7981 Mon Sep 17 00:00:00 2001 From: SJ Park Date: Sun, 28 Jun 2026 14:54:40 -0700 Subject: samples/damon/wsse: handle damon_start() failure Patch series "samples/damon: handle damon_{start,stop}() failures". All DAMON sample modules are not correctly handling failures from damon_start(). Among those, mtier also has an additional problem for handling of damon_stop() failures. wsse and prcl also have a problem in their damon_call() failure handling. As a result, memory leaks, next DAMON operation disruptions, and use-after-free can happen. Fix those. Note that only the damon_start() failure caused issues can reliably be reproduced. Reproducing those issues require the admin permission, though. This patch (of 6): damon_sample_wsse_start() callers assume it will clean up resources when it fails. And the function does the cleanup for context buildup failures. However, it is not doing the cleanup for damon_start() failure. As a result, when damon_start() fails, it leaks the memory for DAMON context. Free the context in case of the failure to fix the issues. Note that the issue can reliably be reproduced because the module calls damon_start() in the exclusive mode. For example, $ sudo damo start $ echo $$ | sudo tee /sys/module/damon_sample_wsse/parameters/target_pid $ echo Y | sudo tee /sys/module/damon_sample_wsse/parameters/enabled $ sudo cat /proc/allocinfo | grep damon_new_ctx Because the first command is running another DAMON instance, the third command fails the damon_start() call because the new DAMON instance cannot exclusively run. And without this fix, by repeating the third and the fourth commands above, we can show the memory consumption is only increasing due to the leaks. It requires the sudo permission though. The issue was discovered [1] by Sashiko. Link: https://lore.kernel.org/20260628215447.96166-2-sj@kernel.org Link: https://lore.kernel.org/20260609145814.70163-1-sj@kernel.org [1] Fixes: b757c6cfc696 ("samples/damon/wsse: start and stop DAMON as the user requests") Signed-off-by: SJ Park Reviewed-by: Zenghui Yu Cc: # 6.14.x Signed-off-by: Andrew Morton --- samples/damon/wsse.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'samples') diff --git a/samples/damon/wsse.c b/samples/damon/wsse.c index 799ad4443943..bbd9392ab5b3 100644 --- a/samples/damon/wsse.c +++ b/samples/damon/wsse.c @@ -87,8 +87,10 @@ static int damon_sample_wsse_start(void) target->pid = target_pidp; err = damon_start(&ctx, 1, true); - if (err) + if (err) { + damon_destroy_ctx(ctx); return err; + } repeat_call_control.data = ctx; return damon_call(ctx, &repeat_call_control); } -- cgit From 8b724349229bb6ebbf781178be011ba9bc2cca57 Mon Sep 17 00:00:00 2001 From: SJ Park Date: Sun, 28 Jun 2026 14:54:41 -0700 Subject: samples/damon/prcl: handle damon_start() failure damon_sample_prcl_start() callers assume it will clean up resources when it fails. And the function does the cleanup for context buildup failures. However, it is not doing the cleanup for damon_start() failure. As a result, when damon_start() fails, it leaks the memory for DAMON context. Free the context in case of the failure to fix the issues. Note that the issue can reliably be reproduced because the module calls damon_start() in the exclusive mode. For example, $ sudo damo start $ echo $$ | sudo tee /sys/module/damon_sample_prcl/parameters/target_pid $ echo Y | sudo tee /sys/module/damon_sample_prcl/parameters/enabled $ sudo cat /proc/allocinfo | grep damon_new_ctx Because the first command is running another DAMON instance, the third command fails the damon_start() call because the new DAMON instance cannot exclusively run. And without this fix, by repeating the third and the fourth commands above, we can show the memory consumption is only increasing due to the leaks. It requires the sudo permission though. The issue was discovered [1] by Sashiko. Link: https://lore.kernel.org/20260628215447.96166-3-sj@kernel.org Link: https://lore.kernel.org/20260609145814.70163-1-sj@kernel.org [1] Fixes: 2aca254620a8 ("samples/damon: introduce a skeleton of a smaple DAMON module for proactive reclamation") Signed-off-by: SJ Park Reviewed-by: Zenghui Yu Cc: # 6.14.x Signed-off-by: Andrew Morton --- samples/damon/prcl.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'samples') diff --git a/samples/damon/prcl.c b/samples/damon/prcl.c index b7c50f2656ce..0db259894691 100644 --- a/samples/damon/prcl.c +++ b/samples/damon/prcl.c @@ -106,8 +106,10 @@ static int damon_sample_prcl_start(void) damon_set_schemes(ctx, &scheme, 1); err = damon_start(&ctx, 1, true); - if (err) + if (err) { + damon_destroy_ctx(ctx); return err; + } repeat_call_control.data = ctx; return damon_call(ctx, &repeat_call_control); -- cgit From c7230d08ee79b13127bd2b45a3648d361ac912fc Mon Sep 17 00:00:00 2001 From: SJ Park Date: Sun, 28 Jun 2026 14:54:42 -0700 Subject: samples/damon/mtier: handle damon_start() failure damon_sample_mtier_start() callers assume it will clean up resources when it fails. And the function does the cleanup for context buildup failures. However, it is not doing the cleanup for damon_start() failure. As a result, when damon_start() fails, it could leak the memory for DAMON context. Also, if damon_start() fails for only the second context, the first context will indefinitely run, and avoid starting other DAMON contexts since it is running in the exclusive mode. Stop possibly started DAMON context and free the contexts in case of the failure to fix the issues. Note that the issue can reliably be reproduced because the module calls damon_start() in the exclusive mode. For example, $ sudo damo start $ echo Y | sudo tee /sys/module/damon_sample_mtier/parameters/enabled $ sudo cat /proc/allocinfo | grep damon_new_ctx Because the first command is running another DAMON instance, the second command fails the damon_start() call because the new DAMON instance cannot exclusively run. And without this fix, by repeating the second and the third commands above, we can show the memory consumption is only increasing due to the leaks. It requires the sudo permission though. The issue was discovered [1] by Sashiko. Link: https://lore.kernel.org/20260628215447.96166-4-sj@kernel.org Link: https://lore.kernel.org/20260608112455.274231F00893@smtp.kernel.org [1] Fixes: 82a08bde3cf7 ("samples/damon: implement a DAMON module for memory tiering") Signed-off-by: SJ Park Reviewed-by: Zenghui Yu Cc: # 6.16.x Signed-off-by: Andrew Morton --- samples/damon/mtier.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'samples') diff --git a/samples/damon/mtier.c b/samples/damon/mtier.c index 3785b0c7ffb1..564212e054de 100644 --- a/samples/damon/mtier.c +++ b/samples/damon/mtier.c @@ -177,6 +177,7 @@ free_out: static int damon_sample_mtier_start(void) { struct damon_ctx *ctx; + int err; ctx = damon_sample_mtier_build_ctx(true); if (!ctx) @@ -188,7 +189,15 @@ static int damon_sample_mtier_start(void) return -ENOMEM; } ctxs[1] = ctx; - return damon_start(ctxs, 2, true); + err = damon_start(ctxs, 2, true); + if (!err) + return 0; + + if (damon_is_running(ctxs[0])) + damon_stop(ctxs, 1); + damon_destroy_ctx(ctxs[0]); + damon_destroy_ctx(ctxs[1]); + return err; } static void damon_sample_mtier_stop(void) -- cgit From 9dc5b6d66fd51b103eff21ed0df3e292f489ebc0 Mon Sep 17 00:00:00 2001 From: SJ Park Date: Sun, 28 Jun 2026 14:54:43 -0700 Subject: samples/damon/mtier: handle damon_stop() failure damon_sample_mtier_stop() assumes its damon_stop() call will always successfully stops the two DAMON contexts. Hence it deallocates the two DAMON contexts after the damon_stop() call. However, if a given context is already stopped, damon_stop() fails and returns an error while letting the DAMON contexts that have not yet stopped keep running. This kind of unexpected early DAMON context stops could happen due to memory allocation failures in kdamond_fn(). Because damon_sample_mtier_stop() just deallocates all DAMON contexts with damon_target and damon_region objects that are linked to the contexts, the execution of the unstopped DAMON context (kdamond) ends up using the memory that freed (use-after-free). Fix the issue by separating the damon_stop() to be invoked per context. Note that DAMON_SYSFS also allows multiple DAMON contexts execution. But, it calls damon_stop() for each context one by one. Hence this issue is only in mtier. For the long term, it would be better to refactor damon_stop() to always ensure stopping all contexts regardless of the failures in the middle. Make this fix in the current way, though, to keep it simple and easy to backport. I will do the refactoring later. The issue was discovered [1] by Sashiko. Link: https://lore.kernel.org/20260628215447.96166-5-sj@kernel.org Link: https://lore.kernel.org/20260609014219.3013-1-sj@kernel.org [1] Fixes: 82a08bde3cf7 ("samples/damon: implement a DAMON module for memory tiering") Signed-off-by: SJ Park Reviewed-by: Zenghui Yu Cc: # 6.16.x Signed-off-by: Andrew Morton --- samples/damon/mtier.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'samples') diff --git a/samples/damon/mtier.c b/samples/damon/mtier.c index 564212e054de..e567f4edd80e 100644 --- a/samples/damon/mtier.c +++ b/samples/damon/mtier.c @@ -202,7 +202,8 @@ static int damon_sample_mtier_start(void) static void damon_sample_mtier_stop(void) { - damon_stop(ctxs, 2); + damon_stop(ctxs, 1); + damon_stop(&ctxs[1], 1); damon_destroy_ctx(ctxs[0]); damon_destroy_ctx(ctxs[1]); } -- cgit From a2c6fa6c23ad87c61e1379b05dc05cf5fed4bf8d Mon Sep 17 00:00:00 2001 From: SJ Park Date: Sun, 28 Jun 2026 14:54:44 -0700 Subject: samples/damon/wsse: stop and free damon ctx when damon_call() fails damon_sample_wsse_start() calls damon_call() right after damon_start() is succeeded. The kdamond that has started by the damon_start() could be terminated by itself before or in the middle of the damon_call() execution. There could be multiple reasons for such a stop including monitoring target process termination and kdamond_fn() internal memory allocation failures. In the case, damon_call() will fail and return an error without cleaning up the DAMON context object. The damon_sample_wsse_start() caller assumes it would clean up the object, though. When the user requests to start DAMON again, damon_sample_wsse_start() is called again, allocates a new DAMON context object and overwrites the pointer for the previous object. As a result, the previous context object is leaked. Safely stop the kdamond and deallocate the context object when the failure is returned. Note that the kdamond should be stopped first, because damon_call() failure means not complete termination of the kdamond but only the fact that the termination process has started. The user impact shouldn't be that significant because the race is not easy to happen, and only up to one DAMON context object can be leaked per race. The issue was discovered [1] by Sashiko. Link: https://lore.kernel.org/20260628215447.96166-6-sj@kernel.org Link: https://lore.kernel.org/20260610034828.4632-1-sj@kernel.org [1] Fixes: cc9c1b8c205b ("samples/damon/wsse: use damon_call() repeat mode instead of damon_callback") Signed-off-by: SJ Park Reviewed-by: Zenghui Yu Cc: # 6.17.x Signed-off-by: Andrew Morton --- samples/damon/wsse.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'samples') diff --git a/samples/damon/wsse.c b/samples/damon/wsse.c index bbd9392ab5b3..ff5e8a890f44 100644 --- a/samples/damon/wsse.c +++ b/samples/damon/wsse.c @@ -92,7 +92,12 @@ static int damon_sample_wsse_start(void) return err; } repeat_call_control.data = ctx; - return damon_call(ctx, &repeat_call_control); + err = damon_call(ctx, &repeat_call_control); + if (err) { + damon_stop(&ctx, 1); + damon_destroy_ctx(ctx); + } + return err; } static void damon_sample_wsse_stop(void) -- cgit From a73fa45d3f0f42c446ae55c5799e3d5ef044cd5d Mon Sep 17 00:00:00 2001 From: SJ Park Date: Sun, 28 Jun 2026 14:54:45 -0700 Subject: samples/damon/prcl: stop and free damon ctx when damon_call() fails damon_sample_prcl_start() calls damon_call() right after damon_start() is succeeded. The kdamond that has started by the damon_start() could be terminated by itself before or in the middle of the damon_call() execution. There could be multiple reasons for such a stop including monitoring target process termination and kdamond_fn() internal memory allocation failures. In the case, damon_call() will fail and return an error without cleaning up the DAMON context object. The damon_sample_prcl_start() caller assumes it would clean up the object, though. When the user requests to start DAMON again, damon_sample_prcl_start() is called again, allocates a new DAMON context object and overwrites the pointer for the previous object. As a result, the previous context object is leaked. Safely stop the kdamond and deallocate the context object when the failure is returned. Note that the kdamond should be stopped first, because damon_call() failure means not complete termination of the kdamond but only the fact that the termination process has started. The user impact shouldn't be that significant because the race is not easy to happen, and only up to one DAMON context object can be leaked per race. The issue was discovered [1] by Sashiko. Link: https://lore.kernel.org/20260628215447.96166-7-sj@kernel.org Link: https://lore.kernel.org/20260610035214.4850-1-sj@kernel.org [1] Fixes: a6c33f1054e3 ("samples/damon/prcl: use damon_call() repeat mode instead of damon_callback") Signed-off-by: SJ Park Reviewed-by: Zenghui Yu Cc: # 6.17.x Signed-off-by: Andrew Morton --- samples/damon/prcl.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'samples') diff --git a/samples/damon/prcl.c b/samples/damon/prcl.c index 0db259894691..edeae145c4a8 100644 --- a/samples/damon/prcl.c +++ b/samples/damon/prcl.c @@ -112,7 +112,12 @@ static int damon_sample_prcl_start(void) } repeat_call_control.data = ctx; - return damon_call(ctx, &repeat_call_control); + err = damon_call(ctx, &repeat_call_control); + if (err) { + damon_stop(&ctx, 1); + damon_destroy_ctx(ctx); + } + return err; } static void damon_sample_prcl_stop(void) -- cgit From 2ab5ed1c2bade928423991d526d879d134b60eec Mon Sep 17 00:00:00 2001 From: Asier Gutierrez Date: Mon, 29 Jun 2026 07:55:35 -0700 Subject: samples/damon: fix typos in Kconfig help text Fix a couple of typos in samples/damon/Kconfig help text. Change "Thps" to "This", and "tierign" to "tiering". Link: https://lore.kernel.org/20260629145538.134832-5-sj@kernel.org Signed-off-by: Asier Gutierrez Signed-off-by: SJ Park Reviewed-by: SJ Park Cc: Akinobu Mita Cc: Brendan Higgins Cc: David Hildenbrand Cc: Doehyun Baek Cc: Jonathan Corbet Cc: "Liam R. Howlett" Cc: Lorenzo Stoakes Cc: Michal Hocko Cc: Mike Rapoport Cc: Philippe Laferriere Cc: Sailesh Nandanavanam Cc: Shuah Khan Cc: Suren Baghdasaryan Cc: Vlastimil Babka Signed-off-by: Andrew Morton --- samples/damon/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'samples') diff --git a/samples/damon/Kconfig b/samples/damon/Kconfig index cbf96fd8a8bf..00be3e6bdd65 100644 --- a/samples/damon/Kconfig +++ b/samples/damon/Kconfig @@ -31,7 +31,7 @@ config SAMPLE_DAMON_MTIER bool "DAMON sample module for memory tiering" depends on DAMON && DAMON_PADDR help - Thps builds DAMON sample module for memory tierign. + This builds DAMON sample module for memory tiering. The module assumes the system is constructed with two NUMA nodes, which seems as local and remote nodes to all CPUs. For example, -- cgit From 5c5df7aa649a5f9e0cc96f8aabd3aae66fce667e Mon Sep 17 00:00:00 2001 From: SJ Park Date: Mon, 6 Jul 2026 07:06:17 -0700 Subject: samples/damon/mtier: do not stop first context for damon_start() failure damon_start() was able to fail while keeping the first context running. mtier hence stops the first context in the case. damon_start() is refactored to avoid that. The error handling is no longer necessary. Remove it. Link: https://lore.kernel.org/20260706140628.87414-3-sj@kernel.org Signed-off-by: SJ Park Signed-off-by: Andrew Morton --- samples/damon/mtier.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'samples') diff --git a/samples/damon/mtier.c b/samples/damon/mtier.c index e567f4edd80e..90881e8bd441 100644 --- a/samples/damon/mtier.c +++ b/samples/damon/mtier.c @@ -193,8 +193,6 @@ static int damon_sample_mtier_start(void) if (!err) return 0; - if (damon_is_running(ctxs[0])) - damon_stop(ctxs, 1); damon_destroy_ctx(ctxs[0]); damon_destroy_ctx(ctxs[1]); return err; -- cgit From 3e734a0514f9d365773e91abe941decfc3e9331c Mon Sep 17 00:00:00 2001 From: SJ Park Date: Mon, 6 Jul 2026 07:06:23 -0700 Subject: samples/damon/mtier: stop all contexts with single damon_stop() call damon_stop() was theoretically able to return failure while keeping the second context for mtier running. mtier stops its contexts one by one with two damon_stop() call for the reason. damon_stop() is refactored to always successfully stop all requested DAMON contexts. The two calls are unnecessary. Use only single damon_stop() call for all contexts. Link: https://lore.kernel.org/20260706140628.87414-9-sj@kernel.org Signed-off-by: SJ Park Signed-off-by: Andrew Morton --- samples/damon/mtier.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'samples') diff --git a/samples/damon/mtier.c b/samples/damon/mtier.c index 90881e8bd441..ac9c24b92ead 100644 --- a/samples/damon/mtier.c +++ b/samples/damon/mtier.c @@ -200,8 +200,7 @@ static int damon_sample_mtier_start(void) static void damon_sample_mtier_stop(void) { - damon_stop(ctxs, 1); - damon_stop(&ctxs[1], 1); + damon_stop(ctxs, 2); damon_destroy_ctx(ctxs[0]); damon_destroy_ctx(ctxs[1]); } -- cgit From cfd843b299298d7dff51bf86b51eee21e47796b7 Mon Sep 17 00:00:00 2001 From: SJ Park Date: Mon, 6 Jul 2026 07:06:25 -0700 Subject: samples/damon/wsse: do not stop ctx for damon_call() failure damon_call() failure was causing the context to be stopped, but asynchronously by the kdamond thread. To handle the race, the caller had to stop the context. damon_call() is updated to do the stop on its own. Remove the damon_stop() call from the damon_call() error handling. Link: https://lore.kernel.org/20260706140628.87414-11-sj@kernel.org Signed-off-by: SJ Park Signed-off-by: Andrew Morton --- samples/damon/wsse.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'samples') diff --git a/samples/damon/wsse.c b/samples/damon/wsse.c index ff5e8a890f44..37fd5da20158 100644 --- a/samples/damon/wsse.c +++ b/samples/damon/wsse.c @@ -93,10 +93,8 @@ static int damon_sample_wsse_start(void) } repeat_call_control.data = ctx; err = damon_call(ctx, &repeat_call_control); - if (err) { - damon_stop(&ctx, 1); + if (err) damon_destroy_ctx(ctx); - } return err; } -- cgit From b1cc60c13be0e560ff651f23e6fea6df8822bf15 Mon Sep 17 00:00:00 2001 From: SJ Park Date: Mon, 6 Jul 2026 07:06:26 -0700 Subject: samples/damon/prcl: do not stop DAMON for damon_call() failure damon_call() failure was causing the context to be stopped, but asynchronously by the kdamond thread. To handle the race, the caller had to stop the context. damon_call() is updated to do the stop on its own. Remove the damon_stop() call from the damon_call() error handling. Link: https://lore.kernel.org/20260706140628.87414-12-sj@kernel.org Signed-off-by: SJ Park Signed-off-by: Andrew Morton --- samples/damon/prcl.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'samples') diff --git a/samples/damon/prcl.c b/samples/damon/prcl.c index edeae145c4a8..842099bd6228 100644 --- a/samples/damon/prcl.c +++ b/samples/damon/prcl.c @@ -113,10 +113,8 @@ static int damon_sample_prcl_start(void) repeat_call_control.data = ctx; err = damon_call(ctx, &repeat_call_control); - if (err) { - damon_stop(&ctx, 1); + if (err) damon_destroy_ctx(ctx); - } return err; } -- cgit