Skip to content

Commit 75c1c2b

Browse files
sj-awstorvalds
authored andcommitted
mm/damon/dbgfs: support multiple contexts
In some use cases, users would want to run multiple monitoring context. For example, if a user wants a high precision monitoring and dedicating multiple CPUs for the job is ok, because DAMON creates one monitoring thread per one context, the user can split the monitoring target regions into multiple small regions and create one context for each region. Or, someone might want to simultaneously monitor different address spaces, e.g., both virtual address space and physical address space. The DAMON's API allows such usage, but 'damon-dbgfs' does not. Therefore, only kernel space DAMON users can do multiple contexts monitoring. This commit allows the user space DAMON users to use multiple contexts monitoring by introducing two new 'damon-dbgfs' debugfs files, 'mk_context' and 'rm_context'. Users can create a new monitoring context by writing the desired name of the new context to 'mk_context'. Then, a new directory with the name and having the files for setting of the context ('attrs', 'target_ids' and 'record') will be created under the debugfs directory. Writing the name of the context to remove to 'rm_context' will remove the related context and directory. Link: https://lkml.kernel.org/r/[email protected] Signed-off-by: SeongJae Park <[email protected]> Reviewed-by: Fernand Sieber <[email protected]> Cc: Alexander Shishkin <[email protected]> Cc: Amit Shah <[email protected]> Cc: Benjamin Herrenschmidt <[email protected]> Cc: Brendan Higgins <[email protected]> Cc: David Hildenbrand <[email protected]> Cc: David Rientjes <[email protected]> Cc: David Woodhouse <[email protected]> Cc: Fan Du <[email protected]> Cc: Greg Kroah-Hartman <[email protected]> Cc: Greg Thelen <[email protected]> Cc: Ingo Molnar <[email protected]> Cc: Joe Perches <[email protected]> Cc: Jonathan Cameron <[email protected]> Cc: Jonathan Corbet <[email protected]> Cc: Leonard Foerster <[email protected]> Cc: Marco Elver <[email protected]> Cc: Markus Boehme <[email protected]> Cc: Maximilian Heyne <[email protected]> Cc: Mel Gorman <[email protected]> Cc: Minchan Kim <[email protected]> Cc: Namhyung Kim <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Rik van Riel <[email protected]> Cc: Shakeel Butt <[email protected]> Cc: Shuah Khan <[email protected]> Cc: Steven Rostedt (VMware) <[email protected]> Cc: Vladimir Davydov <[email protected]> Cc: Vlastimil Babka <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent 429538e commit 75c1c2b

File tree

1 file changed

+193
-2
lines changed

1 file changed

+193
-2
lines changed

mm/damon/dbgfs.c

Lines changed: 193 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
static struct damon_ctx **dbgfs_ctxs;
1919
static int dbgfs_nr_ctxs;
2020
static struct dentry **dbgfs_dirs;
21+
static DEFINE_MUTEX(damon_dbgfs_lock);
2122

2223
/*
2324
* Returns non-empty string on success, negative error code otherwise.
@@ -328,6 +329,186 @@ static struct damon_ctx *dbgfs_new_ctx(void)
328329
return ctx;
329330
}
330331

332+
static void dbgfs_destroy_ctx(struct damon_ctx *ctx)
333+
{
334+
damon_destroy_ctx(ctx);
335+
}
336+
337+
/*
338+
* Make a context of @name and create a debugfs directory for it.
339+
*
340+
* This function should be called while holding damon_dbgfs_lock.
341+
*
342+
* Returns 0 on success, negative error code otherwise.
343+
*/
344+
static int dbgfs_mk_context(char *name)
345+
{
346+
struct dentry *root, **new_dirs, *new_dir;
347+
struct damon_ctx **new_ctxs, *new_ctx;
348+
349+
if (damon_nr_running_ctxs())
350+
return -EBUSY;
351+
352+
new_ctxs = krealloc(dbgfs_ctxs, sizeof(*dbgfs_ctxs) *
353+
(dbgfs_nr_ctxs + 1), GFP_KERNEL);
354+
if (!new_ctxs)
355+
return -ENOMEM;
356+
dbgfs_ctxs = new_ctxs;
357+
358+
new_dirs = krealloc(dbgfs_dirs, sizeof(*dbgfs_dirs) *
359+
(dbgfs_nr_ctxs + 1), GFP_KERNEL);
360+
if (!new_dirs)
361+
return -ENOMEM;
362+
dbgfs_dirs = new_dirs;
363+
364+
root = dbgfs_dirs[0];
365+
if (!root)
366+
return -ENOENT;
367+
368+
new_dir = debugfs_create_dir(name, root);
369+
dbgfs_dirs[dbgfs_nr_ctxs] = new_dir;
370+
371+
new_ctx = dbgfs_new_ctx();
372+
if (!new_ctx) {
373+
debugfs_remove(new_dir);
374+
dbgfs_dirs[dbgfs_nr_ctxs] = NULL;
375+
return -ENOMEM;
376+
}
377+
378+
dbgfs_ctxs[dbgfs_nr_ctxs] = new_ctx;
379+
dbgfs_fill_ctx_dir(dbgfs_dirs[dbgfs_nr_ctxs],
380+
dbgfs_ctxs[dbgfs_nr_ctxs]);
381+
dbgfs_nr_ctxs++;
382+
383+
return 0;
384+
}
385+
386+
static ssize_t dbgfs_mk_context_write(struct file *file,
387+
const char __user *buf, size_t count, loff_t *ppos)
388+
{
389+
char *kbuf;
390+
char *ctx_name;
391+
ssize_t ret = count;
392+
int err;
393+
394+
kbuf = user_input_str(buf, count, ppos);
395+
if (IS_ERR(kbuf))
396+
return PTR_ERR(kbuf);
397+
ctx_name = kmalloc(count + 1, GFP_KERNEL);
398+
if (!ctx_name) {
399+
kfree(kbuf);
400+
return -ENOMEM;
401+
}
402+
403+
/* Trim white space */
404+
if (sscanf(kbuf, "%s", ctx_name) != 1) {
405+
ret = -EINVAL;
406+
goto out;
407+
}
408+
409+
mutex_lock(&damon_dbgfs_lock);
410+
err = dbgfs_mk_context(ctx_name);
411+
if (err)
412+
ret = err;
413+
mutex_unlock(&damon_dbgfs_lock);
414+
415+
out:
416+
kfree(kbuf);
417+
kfree(ctx_name);
418+
return ret;
419+
}
420+
421+
/*
422+
* Remove a context of @name and its debugfs directory.
423+
*
424+
* This function should be called while holding damon_dbgfs_lock.
425+
*
426+
* Return 0 on success, negative error code otherwise.
427+
*/
428+
static int dbgfs_rm_context(char *name)
429+
{
430+
struct dentry *root, *dir, **new_dirs;
431+
struct damon_ctx **new_ctxs;
432+
int i, j;
433+
434+
if (damon_nr_running_ctxs())
435+
return -EBUSY;
436+
437+
root = dbgfs_dirs[0];
438+
if (!root)
439+
return -ENOENT;
440+
441+
dir = debugfs_lookup(name, root);
442+
if (!dir)
443+
return -ENOENT;
444+
445+
new_dirs = kmalloc_array(dbgfs_nr_ctxs - 1, sizeof(*dbgfs_dirs),
446+
GFP_KERNEL);
447+
if (!new_dirs)
448+
return -ENOMEM;
449+
450+
new_ctxs = kmalloc_array(dbgfs_nr_ctxs - 1, sizeof(*dbgfs_ctxs),
451+
GFP_KERNEL);
452+
if (!new_ctxs) {
453+
kfree(new_dirs);
454+
return -ENOMEM;
455+
}
456+
457+
for (i = 0, j = 0; i < dbgfs_nr_ctxs; i++) {
458+
if (dbgfs_dirs[i] == dir) {
459+
debugfs_remove(dbgfs_dirs[i]);
460+
dbgfs_destroy_ctx(dbgfs_ctxs[i]);
461+
continue;
462+
}
463+
new_dirs[j] = dbgfs_dirs[i];
464+
new_ctxs[j++] = dbgfs_ctxs[i];
465+
}
466+
467+
kfree(dbgfs_dirs);
468+
kfree(dbgfs_ctxs);
469+
470+
dbgfs_dirs = new_dirs;
471+
dbgfs_ctxs = new_ctxs;
472+
dbgfs_nr_ctxs--;
473+
474+
return 0;
475+
}
476+
477+
static ssize_t dbgfs_rm_context_write(struct file *file,
478+
const char __user *buf, size_t count, loff_t *ppos)
479+
{
480+
char *kbuf;
481+
ssize_t ret = count;
482+
int err;
483+
char *ctx_name;
484+
485+
kbuf = user_input_str(buf, count, ppos);
486+
if (IS_ERR(kbuf))
487+
return PTR_ERR(kbuf);
488+
ctx_name = kmalloc(count + 1, GFP_KERNEL);
489+
if (!ctx_name) {
490+
kfree(kbuf);
491+
return -ENOMEM;
492+
}
493+
494+
/* Trim white space */
495+
if (sscanf(kbuf, "%s", ctx_name) != 1) {
496+
ret = -EINVAL;
497+
goto out;
498+
}
499+
500+
mutex_lock(&damon_dbgfs_lock);
501+
err = dbgfs_rm_context(ctx_name);
502+
if (err)
503+
ret = err;
504+
mutex_unlock(&damon_dbgfs_lock);
505+
506+
out:
507+
kfree(kbuf);
508+
kfree(ctx_name);
509+
return ret;
510+
}
511+
331512
static ssize_t dbgfs_monitor_on_read(struct file *file,
332513
char __user *buf, size_t count, loff_t *ppos)
333514
{
@@ -370,6 +551,14 @@ static ssize_t dbgfs_monitor_on_write(struct file *file,
370551
return ret;
371552
}
372553

554+
static const struct file_operations mk_contexts_fops = {
555+
.write = dbgfs_mk_context_write,
556+
};
557+
558+
static const struct file_operations rm_contexts_fops = {
559+
.write = dbgfs_rm_context_write,
560+
};
561+
373562
static const struct file_operations monitor_on_fops = {
374563
.read = dbgfs_monitor_on_read,
375564
.write = dbgfs_monitor_on_write,
@@ -378,8 +567,10 @@ static const struct file_operations monitor_on_fops = {
378567
static int __init __damon_dbgfs_init(void)
379568
{
380569
struct dentry *dbgfs_root;
381-
const char * const file_names[] = {"monitor_on"};
382-
const struct file_operations *fops[] = {&monitor_on_fops};
570+
const char * const file_names[] = {"mk_contexts", "rm_contexts",
571+
"monitor_on"};
572+
const struct file_operations *fops[] = {&mk_contexts_fops,
573+
&rm_contexts_fops, &monitor_on_fops};
383574
int i;
384575

385576
dbgfs_root = debugfs_create_dir("damon", NULL);

0 commit comments

Comments
 (0)