]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
6.1-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 16 Jun 2026 12:06:46 +0000 (17:36 +0530)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 16 Jun 2026 12:06:46 +0000 (17:36 +0530)
added patches:
drm-v3d-reject-empty-multisync-extension-to-prevent-infinite-loop.patch
ipmi-ssif-null-thread-on-error.patch
ipmi-ssif-remove-unnecessary-indention.patch
mm-damon-core-implement-damon_kdamond_pid.patch
mm-damon-lru_sort-detect-and-use-fresh-enabled-and-kdamond_pid-values.patch
mm-damon-reclaim-detect-and-use-fresh-enabled-and-kdamond_pid-values.patch

queue-6.1/drm-v3d-reject-empty-multisync-extension-to-prevent-infinite-loop.patch [new file with mode: 0644]
queue-6.1/ipmi-ssif-null-thread-on-error.patch [new file with mode: 0644]
queue-6.1/ipmi-ssif-remove-unnecessary-indention.patch [new file with mode: 0644]
queue-6.1/mm-damon-core-implement-damon_kdamond_pid.patch [new file with mode: 0644]
queue-6.1/mm-damon-lru_sort-detect-and-use-fresh-enabled-and-kdamond_pid-values.patch [new file with mode: 0644]
queue-6.1/mm-damon-reclaim-detect-and-use-fresh-enabled-and-kdamond_pid-values.patch [new file with mode: 0644]
queue-6.1/series

diff --git a/queue-6.1/drm-v3d-reject-empty-multisync-extension-to-prevent-infinite-loop.patch b/queue-6.1/drm-v3d-reject-empty-multisync-extension-to-prevent-infinite-loop.patch
new file mode 100644 (file)
index 0000000..773d7e5
--- /dev/null
@@ -0,0 +1,56 @@
+From fb44d589bf3148e13452185a6e772a7efbf2d684 Mon Sep 17 00:00:00 2001
+From: Ashutosh Desai <ashutoshdesai993@gmail.com>
+Date: Wed, 15 Apr 2026 05:00:00 +0000
+Subject: drm/v3d: Reject empty multisync extension to prevent infinite loop
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Ashutosh Desai <ashutoshdesai993@gmail.com>
+
+commit fb44d589bf3148e13452185a6e772a7efbf2d684 upstream.
+
+v3d_get_extensions() walks a userspace-provided singly-linked list of
+ioctl extensions without any bound on the chain length. A local user
+can craft a self-referential extension (ext->next == &ext) with zero
+in_sync_count and out_sync_count, which bypasses the existing duplicate-
+extension guard:
+
+    if (se->in_sync_count || se->out_sync_count)
+            return -EINVAL;
+
+The guard never fires because v3d_get_multisync_post_deps() returns
+immediately when count is zero, leaving both fields at zero on every
+iteration. The result is an infinite loop in kernel context, blocking
+the calling thread and pegging a CPU core indefinitely.
+
+Fix this by rejecting a multisync extension where both in_sync_count
+and out_sync_count are zero in v3d_get_multisync_submit_deps(). An
+empty multisync carries no synchronization information and serves no
+useful purpose, so returning -EINVAL for such an extension is the
+correct defense against this attack vector.
+
+Fixes: e4165ae8304e ("drm/v3d: add multiple syncobjs support")
+Cc: stable@vger.kernel.org
+Signed-off-by: Ashutosh Desai <ashutoshdesai993@gmail.com>
+Link: https://patch.msgid.link/20260415050000.3816128-1-ashutoshdesai993@gmail.com
+Signed-off-by: MaĆ­ra Canal <mcanal@igalia.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/v3d/v3d_gem.c |    5 +++++
+ 1 file changed, 5 insertions(+)
+
+--- a/drivers/gpu/drm/v3d/v3d_gem.c
++++ b/drivers/gpu/drm/v3d/v3d_gem.c
+@@ -649,6 +649,11 @@ v3d_get_multisync_submit_deps(struct drm
+       if (multisync.pad)
+               return -EINVAL;
++      if (!multisync.in_sync_count && !multisync.out_sync_count) {
++              DRM_DEBUG("Empty multisync extension\n");
++              return -EINVAL;
++      }
++
+       ret = v3d_get_multisync_post_deps(file_priv, data, multisync.out_sync_count,
+                                         multisync.out_syncs);
+       if (ret)
diff --git a/queue-6.1/ipmi-ssif-null-thread-on-error.patch b/queue-6.1/ipmi-ssif-null-thread-on-error.patch
new file mode 100644 (file)
index 0000000..456ea74
--- /dev/null
@@ -0,0 +1,34 @@
+From a8aebe93a4938c0ca1941eeaae821738f869be3d Mon Sep 17 00:00:00 2001
+From: Corey Minyard <corey@minyard.net>
+Date: Tue, 21 Apr 2026 06:50:22 -0500
+Subject: ipmi:ssif: NULL thread on error
+
+From: Corey Minyard <corey@minyard.net>
+
+commit a8aebe93a4938c0ca1941eeaae821738f869be3d upstream.
+
+Cleanup code was checking the thread for NULL, but it was possibly
+a PTR_ERR() in one spot.
+
+Spotted with static analysis.
+
+Link: https://sourceforge.net/p/openipmi/mailman/message/59324676/
+Fixes: 75c486cb1bca ("ipmi:ssif: Clean up kthread on errors")
+Cc: <stable@vger.kernel.org> # 91eb7ec72612: ipmi:ssif: Remove unnecessary indention
+Cc: stable@vger.kernel.org
+Signed-off-by: Corey Minyard <corey@minyard.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/char/ipmi/ipmi_ssif.c |    1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/char/ipmi/ipmi_ssif.c
++++ b/drivers/char/ipmi/ipmi_ssif.c
+@@ -1886,6 +1886,7 @@ static int ssif_probe(struct i2c_client
+                                       "kssif%4.4x", thread_num);
+       if (IS_ERR(ssif_info->thread)) {
+               rv = PTR_ERR(ssif_info->thread);
++              ssif_info->thread = NULL;
+               dev_notice(&ssif_info->client->dev,
+                          "Could not start kernel thread: error %d\n",
+                          rv);
diff --git a/queue-6.1/ipmi-ssif-remove-unnecessary-indention.patch b/queue-6.1/ipmi-ssif-remove-unnecessary-indention.patch
new file mode 100644 (file)
index 0000000..2a07c45
--- /dev/null
@@ -0,0 +1,62 @@
+From 91eb7ec7261254b6875909df767185838598e21e Mon Sep 17 00:00:00 2001
+From: Corey Minyard <corey@minyard.net>
+Date: Mon, 13 Apr 2026 07:09:15 -0500
+Subject: ipmi:ssif: Remove unnecessary indention
+
+From: Corey Minyard <corey@minyard.net>
+
+commit 91eb7ec7261254b6875909df767185838598e21e upstream.
+
+A section was in {} that didn't need to be, move the variable
+definition to the top and set th eindentino properly.
+
+Signed-off-by: Corey Minyard <corey@minyard.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/char/ipmi/ipmi_ssif.c |   28 ++++++++++++----------------
+ 1 file changed, 12 insertions(+), 16 deletions(-)
+
+--- a/drivers/char/ipmi/ipmi_ssif.c
++++ b/drivers/char/ipmi/ipmi_ssif.c
+@@ -1670,6 +1670,7 @@ static int ssif_probe(struct i2c_client
+       int               len = 0;
+       int               i;
+       u8                slave_addr = 0;
++      unsigned int      thread_num;
+       struct ssif_addr_info *addr_info = NULL;
+       mutex_lock(&ssif_infos_mutex);
+@@ -1878,22 +1879,17 @@ static int ssif_probe(struct i2c_client
+       ssif_info->handlers.request_events = request_events;
+       ssif_info->handlers.set_need_watch = ssif_set_need_watch;
+-      {
+-              unsigned int thread_num;
+-
+-              thread_num = ((i2c_adapter_id(ssif_info->client->adapter)
+-                             << 8) |
+-                            ssif_info->client->addr);
+-              init_completion(&ssif_info->wake_thread);
+-              ssif_info->thread = kthread_run(ipmi_ssif_thread, ssif_info,
+-                                             "kssif%4.4x", thread_num);
+-              if (IS_ERR(ssif_info->thread)) {
+-                      rv = PTR_ERR(ssif_info->thread);
+-                      dev_notice(&ssif_info->client->dev,
+-                                 "Could not start kernel thread: error %d\n",
+-                                 rv);
+-                      goto out;
+-              }
++      thread_num = ((i2c_adapter_id(ssif_info->client->adapter) << 8) |
++                    ssif_info->client->addr);
++      init_completion(&ssif_info->wake_thread);
++      ssif_info->thread = kthread_run(ipmi_ssif_thread, ssif_info,
++                                      "kssif%4.4x", thread_num);
++      if (IS_ERR(ssif_info->thread)) {
++              rv = PTR_ERR(ssif_info->thread);
++              dev_notice(&ssif_info->client->dev,
++                         "Could not start kernel thread: error %d\n",
++                         rv);
++              goto out;
+       }
+       dev_set_drvdata(&ssif_info->client->dev, ssif_info);
diff --git a/queue-6.1/mm-damon-core-implement-damon_kdamond_pid.patch b/queue-6.1/mm-damon-core-implement-damon_kdamond_pid.patch
new file mode 100644 (file)
index 0000000..2c2bbf4
--- /dev/null
@@ -0,0 +1,86 @@
+From 4262c53236977de3ceaa3bf2aefdf772c9b874dd Mon Sep 17 00:00:00 2001
+From: SeongJae Park <sj@kernel.org>
+Date: Thu, 15 Jan 2026 07:20:41 -0800
+Subject: mm/damon/core: implement damon_kdamond_pid()
+
+From: SeongJae Park <sj@kernel.org>
+
+commit 4262c53236977de3ceaa3bf2aefdf772c9b874dd upstream.
+
+Patch series "mm/damon: hide kdamond and kdamond_lock from API callers".
+
+'kdamond' and 'kdamond_lock' fields initially exposed to DAMON API callers
+for flexible synchronization and use cases.  As DAMON API became somewhat
+complicated compared to the early days, Keeping those exposed could only
+encourage the API callers to invent more creative but complicated and
+difficult-to-debug use cases.
+
+Fortunately DAMON API callers didn't invent that many creative use cases.
+There exist only two use cases of 'kdamond' and 'kdamond_lock'.  Finding
+whether the kdamond is actively running, and getting the pid of the
+kdamond.  For the first use case, a dedicated API function, namely
+'damon_is_running()' is provided, and all DAMON API callers are using the
+function for the use case.  Hence only the second use case is where the
+fields are directly being used by DAMON API callers.
+
+To prevent future invention of complicated and erroneous use cases of the
+fields, hide the fields from the API callers.  For that, provide new
+dedicated DAMON API functions for the remaining use case, namely
+damon_kdamond_pid(), migrate DAMON API callers to use the new function,
+and mark the fields as private fields.
+
+
+This patch (of 5):
+
+'kdamond' and 'kdamond_lock' are directly being used by DAMON API callers
+for getting the pid of the corresponding kdamond.  To discourage invention
+of creative but complicated and erroneous new usages of the fields that
+require careful synchronization, implement a new API function that can
+simply be used without the manual synchronizations.
+
+Link: https://lkml.kernel.org/r/20260115152047.68415-1-sj@kernel.org
+Link: https://lkml.kernel.org/r/20260115152047.68415-2-sj@kernel.org
+Signed-off-by: SeongJae Park <sj@kernel.org>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/linux/damon.h |    1 +
+ mm/damon/core.c       |   17 +++++++++++++++++
+ 2 files changed, 18 insertions(+)
+
+--- a/include/linux/damon.h
++++ b/include/linux/damon.h
+@@ -572,6 +572,7 @@ static inline unsigned int damon_max_nr_
+ int damon_start(struct damon_ctx **ctxs, int nr_ctxs, bool exclusive);
+ int damon_stop(struct damon_ctx **ctxs, int nr_ctxs);
++int damon_kdamond_pid(struct damon_ctx *ctx);
+ int damon_set_region_biggest_system_ram_default(struct damon_target *t,
+                               unsigned long *start, unsigned long *end);
+--- a/mm/damon/core.c
++++ b/mm/damon/core.c
+@@ -643,6 +643,23 @@ static bool damon_check_reset_time_inter
+       return true;
+ }
++/**
++ * damon_kdamond_pid() - Return pid of a given DAMON context's worker thread.
++ * @ctx:      The DAMON context of the question.
++ *
++ * Return: pid if @ctx is running, negative error code otherwise.
++ */
++int damon_kdamond_pid(struct damon_ctx *ctx)
++{
++      int pid = -EINVAL;
++
++      mutex_lock(&ctx->kdamond_lock);
++      if (ctx->kdamond)
++              pid = ctx->kdamond->pid;
++      mutex_unlock(&ctx->kdamond_lock);
++      return pid;
++}
++
+ /*
+  * Check whether it is time to flush the aggregated information
+  */
diff --git a/queue-6.1/mm-damon-lru_sort-detect-and-use-fresh-enabled-and-kdamond_pid-values.patch b/queue-6.1/mm-damon-lru_sort-detect-and-use-fresh-enabled-and-kdamond_pid-values.patch
new file mode 100644 (file)
index 0000000..7cb8752
--- /dev/null
@@ -0,0 +1,249 @@
+From b98b7ff6025ae82570d4915e083f0cbd8d48b3cf Mon Sep 17 00:00:00 2001
+From: SeongJae Park <sj@kernel.org>
+Date: Sun, 19 Apr 2026 09:10:01 -0700
+Subject: mm/damon/lru_sort: detect and use fresh enabled and kdamond_pid values
+
+From: SeongJae Park <sj@kernel.org>
+
+commit b98b7ff6025ae82570d4915e083f0cbd8d48b3cf upstream.
+
+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/20260419161003.79176-3-sj@kernel.org
+Fixes: 40e983cca927 ("mm/damon: introduce DAMON-based LRU-lists Sorting")
+Co-developed-by: Liew Rui Yan <aethernet65535@gmail.com>
+Signed-off-by: Liew Rui Yan <aethernet65535@gmail.com>
+Signed-off-by: SeongJae Park <sj@kernel.org>
+Cc: <stable@vger.kernel.org> # 6.0.x
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: SeongJae Park <sj@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/linux/damon.h |    1 
+ mm/damon/core.c       |   16 +++++++++
+ mm/damon/lru_sort.c   |   84 +++++++++++++++++++++++++++++++++-----------------
+ 3 files changed, 73 insertions(+), 28 deletions(-)
+
+--- a/include/linux/damon.h
++++ b/include/linux/damon.h
+@@ -572,6 +572,7 @@ static inline unsigned int damon_max_nr_
+ 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,
+--- a/mm/damon/core.c
++++ b/mm/damon/core.c
+@@ -644,6 +644,22 @@ static bool damon_check_reset_time_inter
+ }
+ /**
++ * 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.
+  *
+--- a/mm/damon/lru_sort.c
++++ b/mm/damon/lru_sort.c
+@@ -113,15 +113,6 @@ module_param(monitor_region_start, ulong
+ 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,
+@@ -249,37 +240,32 @@ 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 struct delayed_work damon_lru_sort_timer;
+ static void damon_lru_sort_timer_fn(struct work_struct *work)
+ {
+-      static bool last_enabled;
+       bool now_enabled;
+       now_enabled = enabled;
+-      if (last_enabled != now_enabled) {
+-              if (!damon_lru_sort_turn(now_enabled))
+-                      last_enabled = now_enabled;
+-              else
+-                      enabled = last_enabled;
+-      }
++      if (damon_lru_sort_enabled() == now_enabled)
++              return;
++      damon_lru_sort_turn(now_enabled);
+ }
+ static DECLARE_DELAYED_WORK(damon_lru_sort_timer, damon_lru_sort_timer_fn);
+@@ -301,15 +287,57 @@ static int damon_lru_sort_enabled_store(
+       return 0;
+ }
++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;
diff --git a/queue-6.1/mm-damon-reclaim-detect-and-use-fresh-enabled-and-kdamond_pid-values.patch b/queue-6.1/mm-damon-reclaim-detect-and-use-fresh-enabled-and-kdamond_pid-values.patch
new file mode 100644 (file)
index 0000000..a65d51c
--- /dev/null
@@ -0,0 +1,233 @@
+From 64a140afa5ed1c6f5ba6d451512cbdbbab1ba339 Mon Sep 17 00:00:00 2001
+From: SeongJae Park <sj@kernel.org>
+Date: Sun, 19 Apr 2026 09:10:00 -0700
+Subject: mm/damon/reclaim: detect and use fresh enabled and kdamond_pid values
+
+From: SeongJae Park <sj@kernel.org>
+
+commit 64a140afa5ed1c6f5ba6d451512cbdbbab1ba339 upstream.
+
+Patch series "mm/damon/modules: detect and use fresh status", v3.
+
+DAMON modules including DAMON_RECLAIM, DAMON_LRU_SORT and DAMON_STAT
+commonly expose the kdamond running status via their parameters.  Under
+certain scenarios including wrong user inputs and memory allocation
+failures, those parameter values can be stale.  It can confuse users.  For
+DAMON_RECLAIM and DAMON_LRU_SORT, it even makes the kdamond unable to be
+restarted before the system reboot.
+
+The problem comes from the fact that there are multiple events for the
+status changes and it is difficult to follow up all the scenarios.  Fix
+the issue by detecting and using the status on demand, instead of using a
+cached status that is difficult to be updated.
+
+Patches 1-3 fix the bugs in DAMON_RECLAIM, DAMON_LRU_SORT and DAMON_STAT
+in the order.
+
+
+This patch (of 3):
+
+DAMON_RECLAIM 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_RECLAIM 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_reclaim/parameters
+    #
+    # # start DAMON_RECLAIM
+    # 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/20260419161003.79176-1-sj@kernel.org
+Link: https://lore.kernel.org/20260419161003.79176-2-sj@kernel.org
+Fixes: e035c280f6df ("mm/damon/reclaim: support online inputs update")
+Co-developed-by: Liew Rui Yan <aethernet65535@gmail.com>
+Signed-off-by: Liew Rui Yan <aethernet65535@gmail.com>
+Signed-off-by: SeongJae Park <sj@kernel.org>
+Cc: <stable@vger.kernel.org> # 5.19.x
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: SeongJae Park <sj@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ mm/damon/reclaim.c |   84 +++++++++++++++++++++++++++++++++++------------------
+ 1 file changed, 56 insertions(+), 28 deletions(-)
+
+--- a/mm/damon/reclaim.c
++++ b/mm/damon/reclaim.c
+@@ -100,15 +100,6 @@ module_param(monitor_region_start, ulong
+ static unsigned long monitor_region_end __read_mostly;
+ module_param(monitor_region_end, ulong, 0600);
+-/*
+- * PID of the DAMON thread
+- *
+- * If DAMON_RECLAIM 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_reclaim_stat;
+ DEFINE_DAMON_MODULES_DAMOS_STATS_PARAMS(damon_reclaim_stat,
+               reclaim_tried_regions, reclaimed_regions, quota_exceeds);
+@@ -184,37 +175,32 @@ static int damon_reclaim_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_reclaim_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_reclaim_enabled(void)
++{
++      if (!ctx)
++              return false;
++      return damon_is_running(ctx);
+ }
+ static struct delayed_work damon_reclaim_timer;
+ static void damon_reclaim_timer_fn(struct work_struct *work)
+ {
+-      static bool last_enabled;
+       bool now_enabled;
+       now_enabled = enabled;
+-      if (last_enabled != now_enabled) {
+-              if (!damon_reclaim_turn(now_enabled))
+-                      last_enabled = now_enabled;
+-              else
+-                      enabled = last_enabled;
+-      }
++      if (damon_reclaim_enabled() != now_enabled)
++              return;
++      damon_reclaim_turn(now_enabled);
+ }
+ static DECLARE_DELAYED_WORK(damon_reclaim_timer, damon_reclaim_timer_fn);
+@@ -236,15 +222,57 @@ static int damon_reclaim_enabled_store(c
+       return 0;
+ }
++static int damon_reclaim_enabled_load(char *buffer,
++              const struct kernel_param *kp)
++{
++      return sprintf(buffer, "%c\n", damon_reclaim_enabled() ? 'Y' : 'N');
++}
++
+ static const struct kernel_param_ops enabled_param_ops = {
+       .set = damon_reclaim_enabled_store,
+-      .get = param_get_bool,
++      .get = damon_reclaim_enabled_load,
+ };
+ module_param_cb(enabled, &enabled_param_ops, &enabled, 0600);
+ MODULE_PARM_DESC(enabled,
+       "Enable or disable DAMON_RECLAIM (default: disabled)");
++static int damon_reclaim_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_reclaim_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_reclaim_kdamond_pid_store,
++      .get = damon_reclaim_kdamond_pid_load,
++};
++
++/*
++ * PID of the DAMON thread
++ *
++ * If DAMON_RECLAIM 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_reclaim_handle_commit_inputs(void)
+ {
+       int err;
index 8681530198c73ad68390ff4ca055fb46c1b0bb43..f8274a99676b1da5c29e9d0a458b2227b638548b 100644 (file)
@@ -504,3 +504,9 @@ mm-damon-core-use-time_in_range_open-for-damos-quota-window-start.patch
 mm-damon-core-disallow-time-quota-setting-zero-esz.patch
 usb-typec-tcpm-reset-internal-port-states-on-soft-reset-ams.patch
 lib-crypto-mpi-fix-integer-underflow-in-mpi_read_raw_from_sgl.patch
+ipmi-ssif-remove-unnecessary-indention.patch
+ipmi-ssif-null-thread-on-error.patch
+mm-damon-core-implement-damon_kdamond_pid.patch
+mm-damon-lru_sort-detect-and-use-fresh-enabled-and-kdamond_pid-values.patch
+mm-damon-reclaim-detect-and-use-fresh-enabled-and-kdamond_pid-values.patch
+drm-v3d-reject-empty-multisync-extension-to-prevent-infinite-loop.patch