Skip to content

Commit 9f7b053

Browse files
sjp38torvalds
authored andcommitted
mm/damon: let monitoring operations can be registered and selected
In-kernel DAMON user code like DAMON debugfs interface should set 'struct damon_operations' of its 'struct damon_ctx' on its own. Therefore, the client code should depend on all supporting monitoring operations implementations that it could use. For example, DAMON debugfs interface depends on both vaddr and paddr, while some of the users are not always interested in both. To minimize such unnecessary dependencies, this commit makes the monitoring operations can be registered by implementing code and then dynamically selected by the user code without build-time dependency. Link: https://lkml.kernel.org/r/20220215184603.1479-3-sj@kernel.org Signed-off-by: SeongJae Park <sj@kernel.org> Cc: David Rientjes <rientjes@google.com> Cc: Xin Hao <xhao@linux.alibaba.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
1 parent f7d911c commit 9f7b053

2 files changed

Lines changed: 84 additions & 0 deletions

File tree

include/linux/damon.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,11 +253,24 @@ struct damos {
253253
struct list_head list;
254254
};
255255

256+
/**
257+
* enum damon_ops_id - Identifier for each monitoring operations implementation
258+
*
259+
* @DAMON_OPS_VADDR: Monitoring operations for virtual address spaces
260+
* @DAMON_OPS_PADDR: Monitoring operations for the physical address space
261+
*/
262+
enum damon_ops_id {
263+
DAMON_OPS_VADDR,
264+
DAMON_OPS_PADDR,
265+
NR_DAMON_OPS,
266+
};
267+
256268
struct damon_ctx;
257269

258270
/**
259271
* struct damon_operations - Monitoring operations for given use cases.
260272
*
273+
* @id: Identifier of this operations set.
261274
* @init: Initialize operations-related data structures.
262275
* @update: Update operations-related data structures.
263276
* @prepare_access_checks: Prepare next access check of target regions.
@@ -277,6 +290,8 @@ struct damon_ctx;
277290
* &damon_ctx.sample_interval. Finally, @reset_aggregated is called after each
278291
* &damon_ctx.aggr_interval.
279292
*
293+
* Each &struct damon_operations instance having valid @id can be registered
294+
* via damon_register_ops() and selected by damon_select_ops() later.
280295
* @init should initialize operations-related data structures. For example,
281296
* this could be used to construct proper monitoring target regions and link
282297
* those to @damon_ctx.adaptive_targets.
@@ -301,6 +316,7 @@ struct damon_ctx;
301316
* @cleanup is called from @kdamond just before its termination.
302317
*/
303318
struct damon_operations {
319+
enum damon_ops_id id;
304320
void (*init)(struct damon_ctx *context);
305321
void (*update)(struct damon_ctx *context);
306322
void (*prepare_access_checks)(struct damon_ctx *context);
@@ -489,6 +505,8 @@ int damon_set_attrs(struct damon_ctx *ctx, unsigned long sample_int,
489505
int damon_set_schemes(struct damon_ctx *ctx,
490506
struct damos **schemes, ssize_t nr_schemes);
491507
int damon_nr_running_ctxs(void);
508+
int damon_register_ops(struct damon_operations *ops);
509+
int damon_select_ops(struct damon_ctx *ctx, enum damon_ops_id id);
492510

493511
int damon_start(struct damon_ctx **ctxs, int nr_ctxs);
494512
int damon_stop(struct damon_ctx **ctxs, int nr_ctxs);

mm/damon/core.c

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,72 @@
2525
static DEFINE_MUTEX(damon_lock);
2626
static int nr_running_ctxs;
2727

28+
static DEFINE_MUTEX(damon_ops_lock);
29+
static struct damon_operations damon_registered_ops[NR_DAMON_OPS];
30+
31+
/* Should be called under damon_ops_lock with id smaller than NR_DAMON_OPS */
32+
static bool damon_registered_ops_id(enum damon_ops_id id)
33+
{
34+
struct damon_operations empty_ops = {};
35+
36+
if (!memcmp(&empty_ops, &damon_registered_ops[id], sizeof(empty_ops)))
37+
return false;
38+
return true;
39+
}
40+
41+
/**
42+
* damon_register_ops() - Register a monitoring operations set to DAMON.
43+
* @ops: monitoring operations set to register.
44+
*
45+
* This function registers a monitoring operations set of valid &struct
46+
* damon_operations->id so that others can find and use them later.
47+
*
48+
* Return: 0 on success, negative error code otherwise.
49+
*/
50+
int damon_register_ops(struct damon_operations *ops)
51+
{
52+
int err = 0;
53+
54+
if (ops->id >= NR_DAMON_OPS)
55+
return -EINVAL;
56+
mutex_lock(&damon_ops_lock);
57+
/* Fail for already registered ops */
58+
if (damon_registered_ops_id(ops->id)) {
59+
err = -EINVAL;
60+
goto out;
61+
}
62+
damon_registered_ops[ops->id] = *ops;
63+
out:
64+
mutex_unlock(&damon_ops_lock);
65+
return err;
66+
}
67+
68+
/**
69+
* damon_select_ops() - Select a monitoring operations to use with the context.
70+
* @ctx: monitoring context to use the operations.
71+
* @id: id of the registered monitoring operations to select.
72+
*
73+
* This function finds registered monitoring operations set of @id and make
74+
* @ctx to use it.
75+
*
76+
* Return: 0 on success, negative error code otherwise.
77+
*/
78+
int damon_select_ops(struct damon_ctx *ctx, enum damon_ops_id id)
79+
{
80+
int err = 0;
81+
82+
if (id >= NR_DAMON_OPS)
83+
return -EINVAL;
84+
85+
mutex_lock(&damon_ops_lock);
86+
if (!damon_registered_ops_id(id))
87+
err = -EINVAL;
88+
else
89+
ctx->ops = damon_registered_ops[id];
90+
mutex_unlock(&damon_ops_lock);
91+
return err;
92+
}
93+
2894
/*
2995
* Construct a damon_region struct
3096
*

0 commit comments

Comments
 (0)