]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
mm/damon/core: introduce repeat mode damon_call()
authorSeongJae Park <sj@kernel.org>
Sat, 12 Jul 2025 19:50:04 +0000 (12:50 -0700)
committerAndrew Morton <akpm@linux-foundation.org>
Sun, 20 Jul 2025 01:59:54 +0000 (18:59 -0700)
damon_call() can be useful for reading or writing DAMON internal data for
one time.  A common pattern of DAMON core usage from DAMON modules is
doing such reads and writes repeatedly, for example, to periodically
update the DAMOS stats.  To do that with damon_call(), callers should call
damon_call() repeatedly, with their own delay loop.  Each caller doing
that is repetitive.  Introduce a repeat mode damon_call().  Callers can
use the mode by setting a new field in damon_call_control.  If the mode is
turned on, damon_call() returns success immediately, and DAMON repeats
invoking the callback function inside the kdamond main loop.

Link: https://lkml.kernel.org/r/20250712195016.151108-3-sj@kernel.org
Signed-off-by: SeongJae Park <sj@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
include/linux/damon.h
mm/damon/core.c

index 562c7876ba88f2489b9485ff7ea3874df81a9c0b..b83987275ff9d2cc94fa70368bc394c26ebbd360 100644 (file)
@@ -659,6 +659,7 @@ struct damon_callback {
  *
  * @fn:                        Function to be called back.
  * @data:              Data that will be passed to @fn.
+ * @repeat:            Repeat invocations.
  * @return_code:       Return code from @fn invocation.
  *
  * Control damon_call(), which requests specific kdamond to invoke a given
@@ -667,6 +668,7 @@ struct damon_callback {
 struct damon_call_control {
        int (*fn)(void *data);
        void *data;
+       bool repeat;
        int return_code;
 /* private: internal use only */
        /* informs if the kdamond finished handling of the request */
index b0a0b98f68898965c821902283a18165336f687c..ffb87497dbb5ed09c299869644972f9a3754a127 100644 (file)
@@ -1379,8 +1379,9 @@ bool damon_is_running(struct damon_ctx *ctx)
  *
  * Ask DAMON worker thread (kdamond) of @ctx to call a function with an
  * argument data that respectively passed via &damon_call_control->fn and
- * &damon_call_control->data of @control, and wait until the kdamond finishes
- * handling of the request.
+ * &damon_call_control->data of @control.  If &damon_call_control->repeat of
+ * @control is set, further wait until the kdamond finishes handling of the
+ * request.  Otherwise, return as soon as the request is made.
  *
  * The kdamond executes the function with the argument in the main loop, just
  * after a sampling of the iteration is finished.  The function can hence
@@ -1392,7 +1393,8 @@ bool damon_is_running(struct damon_ctx *ctx)
  */
 int damon_call(struct damon_ctx *ctx, struct damon_call_control *control)
 {
-       init_completion(&control->completion);
+       if (!control->repeat)
+               init_completion(&control->completion);
        control->canceled = false;
        INIT_LIST_HEAD(&control->list);
 
@@ -1401,6 +1403,8 @@ int damon_call(struct damon_ctx *ctx, struct damon_call_control *control)
        mutex_unlock(&ctx->call_controls_lock);
        if (!damon_is_running(ctx))
                return -EINVAL;
+       if (control->repeat)
+               return 0;
        wait_for_completion(&control->completion);
        if (control->canceled)
                return -ECANCELED;
@@ -2429,6 +2433,7 @@ static void kdamond_usleep(unsigned long usecs)
 static void kdamond_call(struct damon_ctx *ctx, bool cancel)
 {
        struct damon_call_control *control;
+       LIST_HEAD(repeat_controls);
        int ret = 0;
 
        while (true) {
@@ -2437,7 +2442,7 @@ static void kdamond_call(struct damon_ctx *ctx, bool cancel)
                                struct damon_call_control, list);
                mutex_unlock(&ctx->call_controls_lock);
                if (!control)
-                       return;
+                       break;
                if (cancel) {
                        control->canceled = true;
                } else {
@@ -2447,8 +2452,18 @@ static void kdamond_call(struct damon_ctx *ctx, bool cancel)
                mutex_lock(&ctx->call_controls_lock);
                list_del(&control->list);
                mutex_unlock(&ctx->call_controls_lock);
-               complete(&control->completion);
+               if (!control->repeat)
+                       complete(&control->completion);
+               else
+                       list_add(&control->list, &repeat_controls);
        }
+       control = list_first_entry_or_null(&repeat_controls,
+                       struct damon_call_control, list);
+       if (!control || cancel)
+               return;
+       mutex_lock(&ctx->call_controls_lock);
+       list_add_tail(&control->list, &ctx->call_controls);
+       mutex_unlock(&ctx->call_controls_lock);
 }
 
 /* Returns negative error code if it's not activated but should return */