The kdamond_call() function is executed repeatedly in the kdamond_fn() kernel thread. The kdamond_call() function is implemented as a while loop. Therefore, it is important to improve the list processing logic here to ensure faster execution of control->fn(). For ease of explanation, the data structure names will be abbreviated as follows: damon_call_control.list: C.list ctx->call_controls: CTX.head repeat_controls: R.head the execution flow of the while loop of the kdamond_call() function, Before modification: Old while loop: CTX.head <-----> C.list <-----> C.list <----> C.list ^ | | | if (C.repeat) if (!C.repeat) restore: only one | | list_add_tail() list_del() list_del() | | | + | complete() R.head <------ list_add() To process C.repeat above, we use an additional list, repeat_controls. The process of adding C.list to repeat_controls and then restoring it back to CTX.head is complex and inefficient. Furthermore, there's the problem of restoring only a single C.list to CTX.head. Below, repeat_controls is removed and the existing CTX.head is modified to loop once(1st rotation). This simplifies list processing and creates a more efficient structure. Modified while loop: Not used repeat_controls: CTX.head <-----> C.list <-----> C.list <----> C.list <-------+ | | | if (C.repeat) if (!C.repeat) | | | | list_del() list_del() | | | | | complete() | | | first --------> list_add_tail() -----------+ if (C.list == first) break; Signed-off-by: JaeJoon Jung --- mm/damon/core.c | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/mm/damon/core.c b/mm/damon/core.c index 824aa8f22db3..babad37719b6 100644 --- a/mm/damon/core.c +++ b/mm/damon/core.c @@ -2554,42 +2554,43 @@ 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; + struct damon_call_control *control, *first = NULL; + unsigned int idx = 0; while (true) { mutex_lock(&ctx->call_controls_lock); control = list_first_entry_or_null(&ctx->call_controls, struct damon_call_control, list); mutex_unlock(&ctx->call_controls_lock); - if (!control) + + /* check control empty or 1st rotation */ + if (!control || control == first) break; - if (cancel) { + + if (++idx == 1) + first = control; + + if (cancel) control->canceled = true; - } else { - ret = control->fn(control->data); - control->return_code = ret; - } + else + control->return_code = control->fn(control->data); + mutex_lock(&ctx->call_controls_lock); list_del(&control->list); mutex_unlock(&ctx->call_controls_lock); + if (!control->repeat) { + /* run control->fn() one time */ complete(&control->completion); } else if (control->canceled && control->dealloc_on_cancel) { kfree(control); - continue; } else { - list_add(&control->list, &repeat_controls); + /* to repeat next time */ + mutex_lock(&ctx->call_controls_lock); + list_add_tail(&control->list, &ctx->call_controls); + mutex_unlock(&ctx->call_controls_lock); } } - 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 */ -- 2.43.0