* [RFC PATCH 1/4] mm/damon/core: handle NULL ctx parameter in damon_call()
2026-08-13 3:49 [RFC PATCH 0/4] mm/damon: allow NULL or unstarted damon_ctx parameter for damon_call() SJ Park
@ 2026-08-13 3:49 ` SJ Park
2026-08-13 8:33 ` Gutierrez Asier
2026-08-13 3:49 ` [RFC PATCH 2/4] mm/damon/core: set ctx->call_controls_obsolete in damon_new_ctx() SJ Park
` (2 subsequent siblings)
3 siblings, 1 reply; 6+ messages in thread
From: SJ Park @ 2026-08-13 3:49 UTC (permalink / raw)
Cc: SJ Park, Andrew Morton, damon, linux-kernel, linux-mm
When NULL damon_ctx pointer parameter is passed, damon_call() could do
NULL dereference. The caller is responsible to avoid that. It is easy
to forget, and there are many damon_call() callers. Meanwhile,
damon_call() is never meant to be performance critical. It uses mutex
and completion. Add the NULL pointer check inside damon_call() so that
callers can pass the parameter without NULL checks.
Signed-off-by: SJ Park <sj@kernel.org>
---
mm/damon/core.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/mm/damon/core.c b/mm/damon/core.c
index 92631a36d7b51..5882f9c94c47f 100644
--- a/mm/damon/core.c
+++ b/mm/damon/core.c
@@ -2188,6 +2188,8 @@ int damon_kdamond_pid(struct damon_ctx *ctx)
*/
int damon_call(struct damon_ctx *ctx, struct damon_call_control *control)
{
+ if (!ctx)
+ return -EINVAL;
if (!control->repeat)
init_completion(&control->completion);
control->canceled = false;
--
2.47.3
^ permalink raw reply related [flat|nested] 6+ messages in thread* Re: [RFC PATCH 1/4] mm/damon/core: handle NULL ctx parameter in damon_call()
2026-08-13 3:49 ` [RFC PATCH 1/4] mm/damon/core: handle NULL ctx parameter in damon_call() SJ Park
@ 2026-08-13 8:33 ` Gutierrez Asier
0 siblings, 0 replies; 6+ messages in thread
From: Gutierrez Asier @ 2026-08-13 8:33 UTC (permalink / raw)
To: SJ Park; +Cc: Andrew Morton, damon, linux-kernel, linux-mm
Hi SJ,
On 8/13/2026 6:49 AM, SJ Park wrote:
> When NULL damon_ctx pointer parameter is passed, damon_call() could do
> NULL dereference. The caller is responsible to avoid that. It is easy
> to forget, and there are many damon_call() callers. Meanwhile,
> damon_call() is never meant to be performance critical. It uses mutex
> and completion. Add the NULL pointer check inside damon_call() so that
> callers can pass the parameter without NULL checks.
>
> Signed-off-by: SJ Park <sj@kernel.org>
> ---
> mm/damon/core.c | 2 ++
> 1 file changed, 2 insertions(+)
>
> diff --git a/mm/damon/core.c b/mm/damon/core.c
> index 92631a36d7b51..5882f9c94c47f 100644
> --- a/mm/damon/core.c
> +++ b/mm/damon/core.c
> @@ -2188,6 +2188,8 @@ int damon_kdamond_pid(struct damon_ctx *ctx)
> */
> int damon_call(struct damon_ctx *ctx, struct damon_call_control *control)
> {
> + if (!ctx)
> + return -EINVAL;
> if (!control->repeat)
> init_completion(&control->completion);
> control->canceled = false;
I know that this is a minor optimization, but how about moving INIT_LIST_HEAD(&control->list)
to right before list_add_tail?
It doesn't make sense to initialize the list before checking call_controls_obsolete.
Maybe this suggestion should go in a different patch.
--
Asier Gutierrez
Huawei
^ permalink raw reply [flat|nested] 6+ messages in thread
* [RFC PATCH 2/4] mm/damon/core: set ctx->call_controls_obsolete in damon_new_ctx()
2026-08-13 3:49 [RFC PATCH 0/4] mm/damon: allow NULL or unstarted damon_ctx parameter for damon_call() SJ Park
2026-08-13 3:49 ` [RFC PATCH 1/4] mm/damon/core: handle NULL ctx parameter in damon_call() SJ Park
@ 2026-08-13 3:49 ` SJ Park
2026-08-13 3:49 ` [RFC PATCH 3/4] mm/damon/reclaim: remove unnecessary damon_call() param validation SJ Park
2026-08-13 3:49 ` [RFC PATCH 4/4] mm/damon/lru_sort: " SJ Park
3 siblings, 0 replies; 6+ messages in thread
From: SJ Park @ 2026-08-13 3:49 UTC (permalink / raw)
Cc: SJ Park, Andrew Morton, damon, linux-kernel, linux-mm
damon_ctx->call_controls_obsolete is used to disallow damon_call()
requests when the request cannot be served. The field is unset and set
when the context execution is started and terminated, respectively. The
intention is to allow damon_call() requests only while the context is
actively being executed.
damon_ctx constructor, damon_new_ctx() unsets the field, though. As a
result, passing the damon_ctx parameter that never successfully
damon_start()-ed to damon_call() can indefinitely hang. The callers
should ensure to avoid the case. Such parameter validation is not
always simple. Actually such bugs in DAMON_RECLAIM and DAMON_LRU_SORT
have been found and fixed [1].
Set the field in damon_new_ctx(), so that DAMON API callers can pass the
context parameter to damon_call() without the additional check.
[1] https://lore.kernel.org/20260803134646.16640-1-sj@kernel.org
Signed-off-by: SJ Park <sj@kernel.org>
---
mm/damon/core.c | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/mm/damon/core.c b/mm/damon/core.c
index 5882f9c94c47f..5a92e4fac6d92 100644
--- a/mm/damon/core.c
+++ b/mm/damon/core.c
@@ -920,6 +920,7 @@ struct damon_ctx *damon_new_ctx(void)
INIT_LIST_HEAD(&ctx->adaptive_targets);
INIT_LIST_HEAD(&ctx->schemes);
+ ctx->call_controls_obsolete = true;
prandom_seed_state(&ctx->rnd_state, get_random_u64());
return ctx;
@@ -2178,10 +2179,6 @@ int damon_kdamond_pid(struct damon_ctx *ctx)
* synchronization. The return value of the function will be saved in
* &damon_call_control->return_code.
*
- * Note that this function should be called only after damon_start() with the
- * @ctx has succeeded. Otherwise, this function could fall into an indefinite
- * wait.
- *
* When this function is failed, the @ctx is guaranteed to be stopped.
*
* Return: 0 on success, negative error code otherwise.
--
2.47.3
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [RFC PATCH 3/4] mm/damon/reclaim: remove unnecessary damon_call() param validation
2026-08-13 3:49 [RFC PATCH 0/4] mm/damon: allow NULL or unstarted damon_ctx parameter for damon_call() SJ Park
2026-08-13 3:49 ` [RFC PATCH 1/4] mm/damon/core: handle NULL ctx parameter in damon_call() SJ Park
2026-08-13 3:49 ` [RFC PATCH 2/4] mm/damon/core: set ctx->call_controls_obsolete in damon_new_ctx() SJ Park
@ 2026-08-13 3:49 ` SJ Park
2026-08-13 3:49 ` [RFC PATCH 4/4] mm/damon/lru_sort: " SJ Park
3 siblings, 0 replies; 6+ messages in thread
From: SJ Park @ 2026-08-13 3:49 UTC (permalink / raw)
Cc: SJ Park, Andrew Morton, damon, linux-kernel, linux-mm
DAMON_RECLAIM avoids passing NULL or unstarted damon_ctx to damon_call()
with its own validation. The validation is no longer needed, because
the DAMON core layer now handles the corner cases itself. Remove the
unnecessary check.
Signed-off-by: SJ Park <sj@kernel.org>
---
mm/damon/reclaim.c | 8 --------
1 file changed, 8 deletions(-)
diff --git a/mm/damon/reclaim.c b/mm/damon/reclaim.c
index 45d5557cc575a..42a2c9cb13431 100644
--- a/mm/damon/reclaim.c
+++ b/mm/damon/reclaim.c
@@ -271,8 +271,6 @@ static int damon_reclaim_commit_inputs_fn(void *arg)
return damon_reclaim_apply_parameters();
}
-static bool damon_reclaim_damon_has_started;
-
static int damon_reclaim_commit_inputs_store(const char *val,
const struct kernel_param *kp)
{
@@ -293,10 +291,6 @@ static int damon_reclaim_commit_inputs_store(const char *val,
if (!commit_inputs_request)
return 0;
- /* Skip damon_call() if ctx has not successfully started. */
- if (!damon_reclaim_damon_has_started)
- return -EINVAL;
-
err = damon_call(ctx, &control);
return err ? err : control.return_code;
@@ -343,8 +337,6 @@ static int damon_reclaim_turn(bool on)
err = damon_start(&ctx, 1, true);
if (err)
return err;
- if (!damon_reclaim_damon_has_started)
- damon_reclaim_damon_has_started = true;
return damon_call(ctx, &call_control);
}
--
2.47.3
^ permalink raw reply related [flat|nested] 6+ messages in thread* [RFC PATCH 4/4] mm/damon/lru_sort: remove unnecessary damon_call() param validation
2026-08-13 3:49 [RFC PATCH 0/4] mm/damon: allow NULL or unstarted damon_ctx parameter for damon_call() SJ Park
` (2 preceding siblings ...)
2026-08-13 3:49 ` [RFC PATCH 3/4] mm/damon/reclaim: remove unnecessary damon_call() param validation SJ Park
@ 2026-08-13 3:49 ` SJ Park
3 siblings, 0 replies; 6+ messages in thread
From: SJ Park @ 2026-08-13 3:49 UTC (permalink / raw)
Cc: SJ Park, Andrew Morton, damon, linux-kernel, linux-mm
DAMON_LRU_SORT avoids passing NULL or unstarted damon_ctx to
damon_call() with its own validation. The validation is no longer
needed, because the DAMON core layer now handles the corner cases
itself. Remove the unnecessary check.
Signed-off-by: SJ Park <sj@kernel.org>
---
mm/damon/lru_sort.c | 8 --------
1 file changed, 8 deletions(-)
diff --git a/mm/damon/lru_sort.c b/mm/damon/lru_sort.c
index bd847829a9907..f25ee7326e87c 100644
--- a/mm/damon/lru_sort.c
+++ b/mm/damon/lru_sort.c
@@ -346,8 +346,6 @@ static int damon_lru_sort_commit_inputs_fn(void *arg)
return damon_lru_sort_apply_parameters();
}
-static bool damon_lru_sort_damon_has_started;
-
static int damon_lru_sort_commit_inputs_store(const char *val,
const struct kernel_param *kp)
{
@@ -368,10 +366,6 @@ static int damon_lru_sort_commit_inputs_store(const char *val,
if (!commit_inputs_request)
return 0;
- /* Skip damon_call() if ctx has not successfully started. */
- if (!damon_lru_sort_damon_has_started)
- return -EINVAL;
-
err = damon_call(ctx, &control);
return err ? err : control.return_code;
@@ -422,8 +416,6 @@ static int damon_lru_sort_turn(bool on)
err = damon_start(&ctx, 1, true);
if (err)
return err;
- if (!damon_lru_sort_damon_has_started)
- damon_lru_sort_damon_has_started = true;
return damon_call(ctx, &call_control);
}
--
2.47.3
^ permalink raw reply related [flat|nested] 6+ messages in thread