mirror of https://github.com/torvalds/linux.git
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: SeongJae Park <sj@kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
This commit is contained in:
parent
004ded6bee
commit
43df7676e5
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
Loading…
Reference in New Issue