Commit 43df7676 authored by SeongJae Park's avatar SeongJae Park Committed by Andrew Morton
Browse files

mm/damon/core: introduce repeat mode damon_call()

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: default avatarSeongJae Park <sj@kernel.org>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
parent 004ded6b
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -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 */
+20 −5
Original line number Diff line number Diff line
@@ -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,6 +1393,7 @@ bool damon_is_running(struct damon_ctx *ctx)
 */
int damon_call(struct damon_ctx *ctx, struct damon_call_control *control)
{
	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);
		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 */