From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3194A25B085; Wed, 13 May 2026 04:47:14 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778647634; cv=none; b=bxMndS6o8Ey5fqaoTir908eppkE4pOaM94ZS7mpGkBBkMv/wY1GI2ichWYWrYukHiUdxV57AuxLInZ7aX+uZPFf9wgMLw1urMSkheQe4kBOGhYtM7lIKcJ49oscgUz06fUneWM4gWdVGp6NopuWW0ip2c2AvgkEuylrpC/l6aa0= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778647634; c=relaxed/simple; bh=H8FJyDizHMYDXw9eQlca0BCU3eZ+oXavbvNJM3HyFxI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=IzITXxwimcQ8kQu1dizzRBfDoJuv90/iSGcp3VxzUGknv9OnW0uyiGkohBFKShOEszEuGT4sZBAYBZSkx9UGGTgQjvfYl4C+I7iLkPqnqMg0NmUyjI7RuHCCohu6kZ4gglDbTsQv7yZumx8jU7979Zhai6U1S+ZJT90z9lgn5Gc= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=gdQ+gFPu; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="gdQ+gFPu" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 973D5C2BCC9; Wed, 13 May 2026 04:47:13 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1778647633; bh=H8FJyDizHMYDXw9eQlca0BCU3eZ+oXavbvNJM3HyFxI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=gdQ+gFPu2sehcBH8GUGoCQlDniTGVclg9HTCjmq46wYgDUuA21RVhHlxA40EQK1/X hBqL0f/zjCOL4tdjZ0Bis1GlaQImke5XfhJUAvexY8LQhgZYl8wT/x3nc/BxV+6nim Cc+2MOwJkdJLQt5Kt51QL2eh+TSNeGJ6/hxN0L/M0ObRhlLyg585WyZMhu8F9ia2NU AV75cpga+F1VJxmi0QoTIblwgcREjFiB4baIvDuomvEJp4d8WeNCiXNPV9bDUcLaqz 6udLngSHbvY9ZV7bSmYg78mvSJhtTAyW3YcU2DpPxx88BmqKkPPYZRnB2iZ7i+Q1LL sJm5JB8Ez820Q== From: SeongJae Park To: stable@vger.kernel.org Cc: SeongJae Park , damon@lists.linux.dev, Liew Rui Yan , Andrew Morton Subject: [PATCH 6.12.y] mm/damon/lru_sort: detect and use fresh enabled and kdamond_pid values Date: Tue, 12 May 2026 21:46:58 -0700 Message-ID: <20260513044700.193786-1-sj@kernel.org> X-Mailer: git-send-email 2.47.3 In-Reply-To: <2026051255-roundup-crushing-4344@gregkh> References: <2026051255-roundup-crushing-4344@gregkh> Precedence: bulk X-Mailing-List: stable@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit DAMON_LRU_SORT updates 'enabled' and 'kdamond_pid' parameter values, which represents the running status of its kdamond, when the user explicitly requests start/stop of the kdamond. The kdamond can, however, be stopped in events other than the explicit user request in the following three events. 1. ctx->regions_score_histogram allocation failure at beginning of the execution, 2. damon_commit_ctx() failure due to invalid user input, and 3. damon_commit_ctx() failure due to its internal allocation failures. Hence, if the kdamond is stopped by the above three events, the values of the status parameters can be stale. Users could show the stale values and be confused. This is already bad, but the real consequence is worse. DAMON_LRU_SORT avoids unnecessary damon_start() and damon_stop() calls based on the 'enabled' parameter value. And the update of 'enabled' parameter value depends on the damon_start() and damon_stop() call results. Hence, once the kdamond has stopped by the unintentional events, the user cannot restart the kdamond before the system reboot. For example, the issue can be reproduced via below steps. # cd /sys/module/damon_lru_sort/parameters # # # start DAMON_LRU_SORT # echo Y > enabled # ps -ef | grep kdamond root 806 2 0 17:53 ? 00:00:00 [kdamond.0] root 808 803 0 17:53 pts/4 00:00:00 grep kdamond # # # commit wrong input to stop kdamond withou explicit stop request # echo 3 > addr_unit # echo Y > commit_inputs bash: echo: write error: Invalid argument # # # confirm kdamond is stopped # ps -ef | grep kdamond root 811 803 0 17:53 pts/4 00:00:00 grep kdamond # # # users casn now show stable status # cat enabled Y # cat kdamond_pid 806 # # # even after fixing the wrong parameter, # # kdamond cannot be restarted. # echo 1 > addr_unit # echo Y > enabled # ps -ef | grep kdamond root 815 803 0 17:54 pts/4 00:00:00 grep kdamond The problem will only rarely happen in real and common setups for the following reasons. The allocation failures are unlikely in such setups since those allocations are arguably too small to fail. Also sane users on real production environments may not commit wrong input parameters. But once it happens, the consequence is quite bad. And the bug is a bug. The issue stems from the fact that there are multiple events that can change the status, and following all the events is challenging. Dynamically detect and use the fresh status for the parameters when those are requested. Link: https://lore.kernel.org/20260513040734.144259-2-sj@kernel.org Link: https://lore.kernel.org/20260419161003.79176-3-sj@kernel.org Fixes: 40e983cca927 ("mm/damon: introduce DAMON-based LRU-lists Sorting") Co-developed-by: Liew Rui Yan Signed-off-by: Liew Rui Yan Signed-off-by: SeongJae Park Cc: # 6.0.x Signed-off-by: Andrew Morton (cherry picked from commit b98b7ff6025ae82570d4915e083f0cbd8d48b3cf) Signed-off-by: SeongJae Park (port parts of 42b7491af14c ("mm/damon/core: introduce damon_call()") and d2b5be741a50 ("mm/damon/sysfs: use DAMON core API damon_is_running()") for damon_is_running() dependency) Cc: Liew Rui Yan Cc: Andrew Morton --- This depends on other two backported patches [1,2]. Please apply this after those. [1] https://lore.kernel.org/20260513040734.144259-1-sj@kernel.org [2] https://lore.kernel.org/20260513040734.144259-2-sj@kernel.org include/linux/damon.h | 1 + mm/damon/core.c | 16 ++++++++ mm/damon/lru_sort.c | 88 +++++++++++++++++++++++++++---------------- 3 files changed, 73 insertions(+), 32 deletions(-) diff --git a/include/linux/damon.h b/include/linux/damon.h index 77f8f05cf26fb..e92e9e8a81375 100644 --- a/include/linux/damon.h +++ b/include/linux/damon.h @@ -778,6 +778,7 @@ static inline unsigned int damon_max_nr_accesses(const struct damon_attrs *attrs int damon_start(struct damon_ctx **ctxs, int nr_ctxs, bool exclusive); int damon_stop(struct damon_ctx **ctxs, int nr_ctxs); +bool damon_is_running(struct damon_ctx *ctx); int damon_kdamond_pid(struct damon_ctx *ctx); int damon_set_region_biggest_system_ram_default(struct damon_target *t, diff --git a/mm/damon/core.c b/mm/damon/core.c index 75d391b4ad72f..df721c13c2ca8 100644 --- a/mm/damon/core.c +++ b/mm/damon/core.c @@ -1163,6 +1163,22 @@ int damon_stop(struct damon_ctx **ctxs, int nr_ctxs) return err; } +/** + * damon_is_running() - Returns if a given DAMON context is running. + * @ctx: The DAMON context to see if running. + * + * Return: true if @ctx is running, false otherwise. + */ +bool damon_is_running(struct damon_ctx *ctx) +{ + bool running; + + mutex_lock(&ctx->kdamond_lock); + running = ctx->kdamond != NULL; + mutex_unlock(&ctx->kdamond_lock); + return running; +} + /** * damon_kdamond_pid() - Return pid of a given DAMON context's worker thread. * @ctx: The DAMON context of the question. diff --git a/mm/damon/lru_sort.c b/mm/damon/lru_sort.c index 5654e31a198a4..4fdc5c76ff109 100644 --- a/mm/damon/lru_sort.c +++ b/mm/damon/lru_sort.c @@ -111,15 +111,6 @@ module_param(monitor_region_start, ulong, 0600); static unsigned long monitor_region_end __read_mostly; module_param(monitor_region_end, ulong, 0600); -/* - * PID of the DAMON thread - * - * If DAMON_LRU_SORT is enabled, this becomes the PID of the worker thread. - * Else, -1. - */ -static int kdamond_pid __read_mostly = -1; -module_param(kdamond_pid, int, 0400); - static struct damos_stat damon_lru_sort_hot_stat; DEFINE_DAMON_MODULES_DAMOS_STATS_PARAMS(damon_lru_sort_hot_stat, lru_sort_tried_hot_regions, lru_sorted_hot_regions, @@ -239,60 +230,93 @@ static int damon_lru_sort_turn(bool on) { int err; - if (!on) { - err = damon_stop(&ctx, 1); - if (!err) - kdamond_pid = -1; - return err; - } + if (!on) + return damon_stop(&ctx, 1); err = damon_lru_sort_apply_parameters(); if (err) return err; - err = damon_start(&ctx, 1, true); - if (err) - return err; - kdamond_pid = ctx->kdamond->pid; - return 0; + return damon_start(&ctx, 1, true); +} + +static bool damon_lru_sort_enabled(void) +{ + if (!ctx) + return false; + return damon_is_running(ctx); } static int damon_lru_sort_enabled_store(const char *val, const struct kernel_param *kp) { - bool is_enabled = enabled; - bool enable; int err; - err = kstrtobool(val, &enable); + err = kstrtobool(val, &enabled); if (err) return err; - if (is_enabled == enable) + if (damon_lru_sort_enabled() == enabled) return 0; /* Called before init function. The function will handle this. */ if (!ctx) - goto set_param_out; + return 0; - err = damon_lru_sort_turn(enable); - if (err) - return err; + return damon_lru_sort_turn(enabled); +} -set_param_out: - enabled = enable; - return err; +static int damon_lru_sort_enabled_load(char *buffer, + const struct kernel_param *kp) +{ + return sprintf(buffer, "%c\n", damon_lru_sort_enabled() ? 'Y' : 'N'); } static const struct kernel_param_ops enabled_param_ops = { .set = damon_lru_sort_enabled_store, - .get = param_get_bool, + .get = damon_lru_sort_enabled_load, }; module_param_cb(enabled, &enabled_param_ops, &enabled, 0600); MODULE_PARM_DESC(enabled, "Enable or disable DAMON_LRU_SORT (default: disabled)"); +static int damon_lru_sort_kdamond_pid_store(const char *val, + const struct kernel_param *kp) +{ + /* + * kdamond_pid is read-only, but kernel command line could write it. + * Do nothing here. + */ + return 0; +} + +static int damon_lru_sort_kdamond_pid_load(char *buffer, + const struct kernel_param *kp) +{ + int kdamond_pid = -1; + + if (ctx) { + kdamond_pid = damon_kdamond_pid(ctx); + if (kdamond_pid < 0) + kdamond_pid = -1; + } + return sprintf(buffer, "%d\n", kdamond_pid); +} + +static const struct kernel_param_ops kdamond_pid_param_ops = { + .set = damon_lru_sort_kdamond_pid_store, + .get = damon_lru_sort_kdamond_pid_load, +}; + +/* + * PID of the DAMON thread + * + * If DAMON_LRU_SORT is enabled, this becomes the PID of the worker thread. + * Else, -1. + */ +module_param_cb(kdamond_pid, &kdamond_pid_param_ops, NULL, 0400); + static int damon_lru_sort_handle_commit_inputs(void) { int err; -- 2.47.3