1// SPDX-License-Identifier: GPL-2.0
2/*
3 * DAMON Debugfs Interface
4 *
5 * Author: SeongJae Park <sj@kernel.org>
6 */
7
8#define pr_fmt(fmt) "damon-dbgfs: " fmt
9
10#include <linux/damon.h>
11#include <linux/debugfs.h>
12#include <linux/file.h>
13#include <linux/mm.h>
14#include <linux/module.h>
15#include <linux/page_idle.h>
16#include <linux/slab.h>
17
18#define DAMON_DBGFS_DEPRECATION_NOTICE \
19 "DAMON debugfs interface is deprecated, so users should move " \
20 "to DAMON_SYSFS. If you cannot, please report your usecase to " \
21 "damon@lists.linux.dev and linux-mm@kvack.org.\n"
22
23static struct damon_ctx **dbgfs_ctxs;
24static int dbgfs_nr_ctxs;
25static struct dentry **dbgfs_dirs;
26static DEFINE_MUTEX(damon_dbgfs_lock);
27
28static void damon_dbgfs_warn_deprecation(void)
29{
30 pr_warn_once(DAMON_DBGFS_DEPRECATION_NOTICE);
31}
32
33/*
34 * Returns non-empty string on success, negative error code otherwise.
35 */
36static char *user_input_str(const char __user *buf, size_t count, loff_t *ppos)
37{
38 char *kbuf;
39 ssize_t ret;
40
41 /* We do not accept continuous write */
42 if (*ppos)
43 return ERR_PTR(error: -EINVAL);
44
45 kbuf = kmalloc(size: count + 1, GFP_KERNEL | __GFP_NOWARN);
46 if (!kbuf)
47 return ERR_PTR(error: -ENOMEM);
48
49 ret = simple_write_to_buffer(to: kbuf, available: count + 1, ppos, from: buf, count);
50 if (ret != count) {
51 kfree(objp: kbuf);
52 return ERR_PTR(error: -EIO);
53 }
54 kbuf[ret] = '\0';
55
56 return kbuf;
57}
58
59static ssize_t dbgfs_attrs_read(struct file *file,
60 char __user *buf, size_t count, loff_t *ppos)
61{
62 struct damon_ctx *ctx = file->private_data;
63 char kbuf[128];
64 int ret;
65
66 mutex_lock(&ctx->kdamond_lock);
67 ret = scnprintf(buf: kbuf, ARRAY_SIZE(kbuf), fmt: "%lu %lu %lu %lu %lu\n",
68 ctx->attrs.sample_interval, ctx->attrs.aggr_interval,
69 ctx->attrs.ops_update_interval,
70 ctx->attrs.min_nr_regions, ctx->attrs.max_nr_regions);
71 mutex_unlock(lock: &ctx->kdamond_lock);
72
73 return simple_read_from_buffer(to: buf, count, ppos, from: kbuf, available: ret);
74}
75
76static ssize_t dbgfs_attrs_write(struct file *file,
77 const char __user *buf, size_t count, loff_t *ppos)
78{
79 struct damon_ctx *ctx = file->private_data;
80 struct damon_attrs attrs;
81 char *kbuf;
82 ssize_t ret;
83
84 kbuf = user_input_str(buf, count, ppos);
85 if (IS_ERR(ptr: kbuf))
86 return PTR_ERR(ptr: kbuf);
87
88 if (sscanf(kbuf, "%lu %lu %lu %lu %lu",
89 &attrs.sample_interval, &attrs.aggr_interval,
90 &attrs.ops_update_interval,
91 &attrs.min_nr_regions,
92 &attrs.max_nr_regions) != 5) {
93 ret = -EINVAL;
94 goto out;
95 }
96
97 mutex_lock(&ctx->kdamond_lock);
98 if (ctx->kdamond) {
99 ret = -EBUSY;
100 goto unlock_out;
101 }
102
103 ret = damon_set_attrs(ctx, attrs: &attrs);
104 if (!ret)
105 ret = count;
106unlock_out:
107 mutex_unlock(lock: &ctx->kdamond_lock);
108out:
109 kfree(objp: kbuf);
110 return ret;
111}
112
113/*
114 * Return corresponding dbgfs' scheme action value (int) for the given
115 * damos_action if the given damos_action value is valid and supported by
116 * dbgfs, negative error code otherwise.
117 */
118static int damos_action_to_dbgfs_scheme_action(enum damos_action action)
119{
120 switch (action) {
121 case DAMOS_WILLNEED:
122 return 0;
123 case DAMOS_COLD:
124 return 1;
125 case DAMOS_PAGEOUT:
126 return 2;
127 case DAMOS_HUGEPAGE:
128 return 3;
129 case DAMOS_NOHUGEPAGE:
130 return 4;
131 case DAMOS_STAT:
132 return 5;
133 default:
134 return -EINVAL;
135 }
136}
137
138static ssize_t sprint_schemes(struct damon_ctx *c, char *buf, ssize_t len)
139{
140 struct damos *s;
141 int written = 0;
142 int rc;
143
144 damon_for_each_scheme(s, c) {
145 rc = scnprintf(buf: &buf[written], size: len - written,
146 fmt: "%lu %lu %u %u %u %u %d %lu %lu %lu %u %u %u %d %lu %lu %lu %lu %lu %lu %lu %lu %lu\n",
147 s->pattern.min_sz_region,
148 s->pattern.max_sz_region,
149 s->pattern.min_nr_accesses,
150 s->pattern.max_nr_accesses,
151 s->pattern.min_age_region,
152 s->pattern.max_age_region,
153 damos_action_to_dbgfs_scheme_action(action: s->action),
154 s->quota.ms, s->quota.sz,
155 s->quota.reset_interval,
156 s->quota.weight_sz,
157 s->quota.weight_nr_accesses,
158 s->quota.weight_age,
159 s->wmarks.metric, s->wmarks.interval,
160 s->wmarks.high, s->wmarks.mid, s->wmarks.low,
161 s->stat.nr_tried, s->stat.sz_tried,
162 s->stat.nr_applied, s->stat.sz_applied,
163 s->stat.qt_exceeds);
164 if (!rc)
165 return -ENOMEM;
166
167 written += rc;
168 }
169 return written;
170}
171
172static ssize_t dbgfs_schemes_read(struct file *file, char __user *buf,
173 size_t count, loff_t *ppos)
174{
175 struct damon_ctx *ctx = file->private_data;
176 char *kbuf;
177 ssize_t len;
178
179 kbuf = kmalloc(size: count, GFP_KERNEL | __GFP_NOWARN);
180 if (!kbuf)
181 return -ENOMEM;
182
183 mutex_lock(&ctx->kdamond_lock);
184 len = sprint_schemes(c: ctx, buf: kbuf, len: count);
185 mutex_unlock(lock: &ctx->kdamond_lock);
186 if (len < 0)
187 goto out;
188 len = simple_read_from_buffer(to: buf, count, ppos, from: kbuf, available: len);
189
190out:
191 kfree(objp: kbuf);
192 return len;
193}
194
195static void free_schemes_arr(struct damos **schemes, ssize_t nr_schemes)
196{
197 ssize_t i;
198
199 for (i = 0; i < nr_schemes; i++)
200 kfree(objp: schemes[i]);
201 kfree(objp: schemes);
202}
203
204/*
205 * Return corresponding damos_action for the given dbgfs input for a scheme
206 * action if the input is valid, negative error code otherwise.
207 */
208static enum damos_action dbgfs_scheme_action_to_damos_action(int dbgfs_action)
209{
210 switch (dbgfs_action) {
211 case 0:
212 return DAMOS_WILLNEED;
213 case 1:
214 return DAMOS_COLD;
215 case 2:
216 return DAMOS_PAGEOUT;
217 case 3:
218 return DAMOS_HUGEPAGE;
219 case 4:
220 return DAMOS_NOHUGEPAGE;
221 case 5:
222 return DAMOS_STAT;
223 default:
224 return -EINVAL;
225 }
226}
227
228/*
229 * Converts a string into an array of struct damos pointers
230 *
231 * Returns an array of struct damos pointers that converted if the conversion
232 * success, or NULL otherwise.
233 */
234static struct damos **str_to_schemes(const char *str, ssize_t len,
235 ssize_t *nr_schemes)
236{
237 struct damos *scheme, **schemes;
238 const int max_nr_schemes = 256;
239 int pos = 0, parsed, ret;
240 unsigned int action_input;
241 enum damos_action action;
242
243 schemes = kmalloc_array(n: max_nr_schemes, size: sizeof(scheme),
244 GFP_KERNEL);
245 if (!schemes)
246 return NULL;
247
248 *nr_schemes = 0;
249 while (pos < len && *nr_schemes < max_nr_schemes) {
250 struct damos_access_pattern pattern = {};
251 struct damos_quota quota = {};
252 struct damos_watermarks wmarks;
253
254 ret = sscanf(&str[pos],
255 "%lu %lu %u %u %u %u %u %lu %lu %lu %u %u %u %u %lu %lu %lu %lu%n",
256 &pattern.min_sz_region, &pattern.max_sz_region,
257 &pattern.min_nr_accesses,
258 &pattern.max_nr_accesses,
259 &pattern.min_age_region,
260 &pattern.max_age_region,
261 &action_input, &quota.ms,
262 &quota.sz, &quota.reset_interval,
263 &quota.weight_sz, &quota.weight_nr_accesses,
264 &quota.weight_age, &wmarks.metric,
265 &wmarks.interval, &wmarks.high, &wmarks.mid,
266 &wmarks.low, &parsed);
267 if (ret != 18)
268 break;
269 action = dbgfs_scheme_action_to_damos_action(dbgfs_action: action_input);
270 if ((int)action < 0)
271 goto fail;
272
273 if (pattern.min_sz_region > pattern.max_sz_region ||
274 pattern.min_nr_accesses > pattern.max_nr_accesses ||
275 pattern.min_age_region > pattern.max_age_region)
276 goto fail;
277
278 if (wmarks.high < wmarks.mid || wmarks.high < wmarks.low ||
279 wmarks.mid < wmarks.low)
280 goto fail;
281
282 pos += parsed;
283 scheme = damon_new_scheme(pattern: &pattern, action, apply_interval_us: 0, quota: &quota,
284 wmarks: &wmarks);
285 if (!scheme)
286 goto fail;
287
288 schemes[*nr_schemes] = scheme;
289 *nr_schemes += 1;
290 }
291 return schemes;
292fail:
293 free_schemes_arr(schemes, nr_schemes: *nr_schemes);
294 return NULL;
295}
296
297static ssize_t dbgfs_schemes_write(struct file *file, const char __user *buf,
298 size_t count, loff_t *ppos)
299{
300 struct damon_ctx *ctx = file->private_data;
301 char *kbuf;
302 struct damos **schemes;
303 ssize_t nr_schemes = 0, ret;
304
305 kbuf = user_input_str(buf, count, ppos);
306 if (IS_ERR(ptr: kbuf))
307 return PTR_ERR(ptr: kbuf);
308
309 schemes = str_to_schemes(str: kbuf, len: count, nr_schemes: &nr_schemes);
310 if (!schemes) {
311 ret = -EINVAL;
312 goto out;
313 }
314
315 mutex_lock(&ctx->kdamond_lock);
316 if (ctx->kdamond) {
317 ret = -EBUSY;
318 goto unlock_out;
319 }
320
321 damon_set_schemes(ctx, schemes, nr_schemes);
322 ret = count;
323 nr_schemes = 0;
324
325unlock_out:
326 mutex_unlock(lock: &ctx->kdamond_lock);
327 free_schemes_arr(schemes, nr_schemes);
328out:
329 kfree(objp: kbuf);
330 return ret;
331}
332
333static ssize_t sprint_target_ids(struct damon_ctx *ctx, char *buf, ssize_t len)
334{
335 struct damon_target *t;
336 int id;
337 int written = 0;
338 int rc;
339
340 damon_for_each_target(t, ctx) {
341 if (damon_target_has_pid(ctx))
342 /* Show pid numbers to debugfs users */
343 id = pid_vnr(pid: t->pid);
344 else
345 /* Show 42 for physical address space, just for fun */
346 id = 42;
347
348 rc = scnprintf(buf: &buf[written], size: len - written, fmt: "%d ", id);
349 if (!rc)
350 return -ENOMEM;
351 written += rc;
352 }
353 if (written)
354 written -= 1;
355 written += scnprintf(buf: &buf[written], size: len - written, fmt: "\n");
356 return written;
357}
358
359static ssize_t dbgfs_target_ids_read(struct file *file,
360 char __user *buf, size_t count, loff_t *ppos)
361{
362 struct damon_ctx *ctx = file->private_data;
363 ssize_t len;
364 char ids_buf[320];
365
366 mutex_lock(&ctx->kdamond_lock);
367 len = sprint_target_ids(ctx, buf: ids_buf, len: 320);
368 mutex_unlock(lock: &ctx->kdamond_lock);
369 if (len < 0)
370 return len;
371
372 return simple_read_from_buffer(to: buf, count, ppos, from: ids_buf, available: len);
373}
374
375/*
376 * Converts a string into an integers array
377 *
378 * Returns an array of integers array if the conversion success, or NULL
379 * otherwise.
380 */
381static int *str_to_ints(const char *str, ssize_t len, ssize_t *nr_ints)
382{
383 int *array;
384 const int max_nr_ints = 32;
385 int nr;
386 int pos = 0, parsed, ret;
387
388 *nr_ints = 0;
389 array = kmalloc_array(n: max_nr_ints, size: sizeof(*array), GFP_KERNEL);
390 if (!array)
391 return NULL;
392 while (*nr_ints < max_nr_ints && pos < len) {
393 ret = sscanf(&str[pos], "%d%n", &nr, &parsed);
394 pos += parsed;
395 if (ret != 1)
396 break;
397 array[*nr_ints] = nr;
398 *nr_ints += 1;
399 }
400
401 return array;
402}
403
404static void dbgfs_put_pids(struct pid **pids, int nr_pids)
405{
406 int i;
407
408 for (i = 0; i < nr_pids; i++)
409 put_pid(pid: pids[i]);
410}
411
412/*
413 * Converts a string into an struct pid pointers array
414 *
415 * Returns an array of struct pid pointers if the conversion success, or NULL
416 * otherwise.
417 */
418static struct pid **str_to_pids(const char *str, ssize_t len, ssize_t *nr_pids)
419{
420 int *ints;
421 ssize_t nr_ints;
422 struct pid **pids;
423
424 *nr_pids = 0;
425
426 ints = str_to_ints(str, len, nr_ints: &nr_ints);
427 if (!ints)
428 return NULL;
429
430 pids = kmalloc_array(n: nr_ints, size: sizeof(*pids), GFP_KERNEL);
431 if (!pids)
432 goto out;
433
434 for (; *nr_pids < nr_ints; (*nr_pids)++) {
435 pids[*nr_pids] = find_get_pid(nr: ints[*nr_pids]);
436 if (!pids[*nr_pids]) {
437 dbgfs_put_pids(pids, nr_pids: *nr_pids);
438 kfree(objp: ints);
439 kfree(objp: pids);
440 return NULL;
441 }
442 }
443
444out:
445 kfree(objp: ints);
446 return pids;
447}
448
449/*
450 * dbgfs_set_targets() - Set monitoring targets.
451 * @ctx: monitoring context
452 * @nr_targets: number of targets
453 * @pids: array of target pids (size is same to @nr_targets)
454 *
455 * This function should not be called while the kdamond is running. @pids is
456 * ignored if the context is not configured to have pid in each target. On
457 * failure, reference counts of all pids in @pids are decremented.
458 *
459 * Return: 0 on success, negative error code otherwise.
460 */
461static int dbgfs_set_targets(struct damon_ctx *ctx, ssize_t nr_targets,
462 struct pid **pids)
463{
464 ssize_t i;
465 struct damon_target *t, *next;
466
467 damon_for_each_target_safe(t, next, ctx) {
468 if (damon_target_has_pid(ctx))
469 put_pid(pid: t->pid);
470 damon_destroy_target(t);
471 }
472
473 for (i = 0; i < nr_targets; i++) {
474 t = damon_new_target();
475 if (!t) {
476 damon_for_each_target_safe(t, next, ctx)
477 damon_destroy_target(t);
478 if (damon_target_has_pid(ctx))
479 dbgfs_put_pids(pids, nr_pids: nr_targets);
480 return -ENOMEM;
481 }
482 if (damon_target_has_pid(ctx))
483 t->pid = pids[i];
484 damon_add_target(ctx, t);
485 }
486
487 return 0;
488}
489
490static ssize_t dbgfs_target_ids_write(struct file *file,
491 const char __user *buf, size_t count, loff_t *ppos)
492{
493 struct damon_ctx *ctx = file->private_data;
494 bool id_is_pid = true;
495 char *kbuf;
496 struct pid **target_pids = NULL;
497 ssize_t nr_targets;
498 ssize_t ret;
499
500 kbuf = user_input_str(buf, count, ppos);
501 if (IS_ERR(ptr: kbuf))
502 return PTR_ERR(ptr: kbuf);
503
504 if (!strncmp(kbuf, "paddr\n", count)) {
505 id_is_pid = false;
506 nr_targets = 1;
507 }
508
509 if (id_is_pid) {
510 target_pids = str_to_pids(str: kbuf, len: count, nr_pids: &nr_targets);
511 if (!target_pids) {
512 ret = -ENOMEM;
513 goto out;
514 }
515 }
516
517 mutex_lock(&ctx->kdamond_lock);
518 if (ctx->kdamond) {
519 if (id_is_pid)
520 dbgfs_put_pids(pids: target_pids, nr_pids: nr_targets);
521 ret = -EBUSY;
522 goto unlock_out;
523 }
524
525 /* remove previously set targets */
526 dbgfs_set_targets(ctx, nr_targets: 0, NULL);
527 if (!nr_targets) {
528 ret = count;
529 goto unlock_out;
530 }
531
532 /* Configure the context for the address space type */
533 if (id_is_pid)
534 ret = damon_select_ops(ctx, id: DAMON_OPS_VADDR);
535 else
536 ret = damon_select_ops(ctx, id: DAMON_OPS_PADDR);
537 if (ret)
538 goto unlock_out;
539
540 ret = dbgfs_set_targets(ctx, nr_targets, pids: target_pids);
541 if (!ret)
542 ret = count;
543
544unlock_out:
545 mutex_unlock(lock: &ctx->kdamond_lock);
546 kfree(objp: target_pids);
547out:
548 kfree(objp: kbuf);
549 return ret;
550}
551
552static ssize_t sprint_init_regions(struct damon_ctx *c, char *buf, ssize_t len)
553{
554 struct damon_target *t;
555 struct damon_region *r;
556 int target_idx = 0;
557 int written = 0;
558 int rc;
559
560 damon_for_each_target(t, c) {
561 damon_for_each_region(r, t) {
562 rc = scnprintf(buf: &buf[written], size: len - written,
563 fmt: "%d %lu %lu\n",
564 target_idx, r->ar.start, r->ar.end);
565 if (!rc)
566 return -ENOMEM;
567 written += rc;
568 }
569 target_idx++;
570 }
571 return written;
572}
573
574static ssize_t dbgfs_init_regions_read(struct file *file, char __user *buf,
575 size_t count, loff_t *ppos)
576{
577 struct damon_ctx *ctx = file->private_data;
578 char *kbuf;
579 ssize_t len;
580
581 kbuf = kmalloc(size: count, GFP_KERNEL | __GFP_NOWARN);
582 if (!kbuf)
583 return -ENOMEM;
584
585 mutex_lock(&ctx->kdamond_lock);
586 if (ctx->kdamond) {
587 mutex_unlock(lock: &ctx->kdamond_lock);
588 len = -EBUSY;
589 goto out;
590 }
591
592 len = sprint_init_regions(c: ctx, buf: kbuf, len: count);
593 mutex_unlock(lock: &ctx->kdamond_lock);
594 if (len < 0)
595 goto out;
596 len = simple_read_from_buffer(to: buf, count, ppos, from: kbuf, available: len);
597
598out:
599 kfree(objp: kbuf);
600 return len;
601}
602
603static int add_init_region(struct damon_ctx *c, int target_idx,
604 struct damon_addr_range *ar)
605{
606 struct damon_target *t;
607 struct damon_region *r, *prev;
608 unsigned long idx = 0;
609 int rc = -EINVAL;
610
611 if (ar->start >= ar->end)
612 return -EINVAL;
613
614 damon_for_each_target(t, c) {
615 if (idx++ == target_idx) {
616 r = damon_new_region(start: ar->start, end: ar->end);
617 if (!r)
618 return -ENOMEM;
619 damon_add_region(r, t);
620 if (damon_nr_regions(t) > 1) {
621 prev = damon_prev_region(r);
622 if (prev->ar.end > r->ar.start) {
623 damon_destroy_region(r, t);
624 return -EINVAL;
625 }
626 }
627 rc = 0;
628 }
629 }
630 return rc;
631}
632
633static int set_init_regions(struct damon_ctx *c, const char *str, ssize_t len)
634{
635 struct damon_target *t;
636 struct damon_region *r, *next;
637 int pos = 0, parsed, ret;
638 int target_idx;
639 struct damon_addr_range ar;
640 int err;
641
642 damon_for_each_target(t, c) {
643 damon_for_each_region_safe(r, next, t)
644 damon_destroy_region(r, t);
645 }
646
647 while (pos < len) {
648 ret = sscanf(&str[pos], "%d %lu %lu%n",
649 &target_idx, &ar.start, &ar.end, &parsed);
650 if (ret != 3)
651 break;
652 err = add_init_region(c, target_idx, ar: &ar);
653 if (err)
654 goto fail;
655 pos += parsed;
656 }
657
658 return 0;
659
660fail:
661 damon_for_each_target(t, c) {
662 damon_for_each_region_safe(r, next, t)
663 damon_destroy_region(r, t);
664 }
665 return err;
666}
667
668static ssize_t dbgfs_init_regions_write(struct file *file,
669 const char __user *buf, size_t count,
670 loff_t *ppos)
671{
672 struct damon_ctx *ctx = file->private_data;
673 char *kbuf;
674 ssize_t ret = count;
675 int err;
676
677 kbuf = user_input_str(buf, count, ppos);
678 if (IS_ERR(ptr: kbuf))
679 return PTR_ERR(ptr: kbuf);
680
681 mutex_lock(&ctx->kdamond_lock);
682 if (ctx->kdamond) {
683 ret = -EBUSY;
684 goto unlock_out;
685 }
686
687 err = set_init_regions(c: ctx, str: kbuf, len: ret);
688 if (err)
689 ret = err;
690
691unlock_out:
692 mutex_unlock(lock: &ctx->kdamond_lock);
693 kfree(objp: kbuf);
694 return ret;
695}
696
697static ssize_t dbgfs_kdamond_pid_read(struct file *file,
698 char __user *buf, size_t count, loff_t *ppos)
699{
700 struct damon_ctx *ctx = file->private_data;
701 char *kbuf;
702 ssize_t len;
703
704 kbuf = kmalloc(size: count, GFP_KERNEL | __GFP_NOWARN);
705 if (!kbuf)
706 return -ENOMEM;
707
708 mutex_lock(&ctx->kdamond_lock);
709 if (ctx->kdamond)
710 len = scnprintf(buf: kbuf, size: count, fmt: "%d\n", ctx->kdamond->pid);
711 else
712 len = scnprintf(buf: kbuf, size: count, fmt: "none\n");
713 mutex_unlock(lock: &ctx->kdamond_lock);
714 if (!len)
715 goto out;
716 len = simple_read_from_buffer(to: buf, count, ppos, from: kbuf, available: len);
717
718out:
719 kfree(objp: kbuf);
720 return len;
721}
722
723static int damon_dbgfs_open(struct inode *inode, struct file *file)
724{
725 damon_dbgfs_warn_deprecation();
726
727 file->private_data = inode->i_private;
728
729 return nonseekable_open(inode, filp: file);
730}
731
732static const struct file_operations attrs_fops = {
733 .open = damon_dbgfs_open,
734 .read = dbgfs_attrs_read,
735 .write = dbgfs_attrs_write,
736};
737
738static const struct file_operations schemes_fops = {
739 .open = damon_dbgfs_open,
740 .read = dbgfs_schemes_read,
741 .write = dbgfs_schemes_write,
742};
743
744static const struct file_operations target_ids_fops = {
745 .open = damon_dbgfs_open,
746 .read = dbgfs_target_ids_read,
747 .write = dbgfs_target_ids_write,
748};
749
750static const struct file_operations init_regions_fops = {
751 .open = damon_dbgfs_open,
752 .read = dbgfs_init_regions_read,
753 .write = dbgfs_init_regions_write,
754};
755
756static const struct file_operations kdamond_pid_fops = {
757 .open = damon_dbgfs_open,
758 .read = dbgfs_kdamond_pid_read,
759};
760
761static void dbgfs_fill_ctx_dir(struct dentry *dir, struct damon_ctx *ctx)
762{
763 const char * const file_names[] = {"attrs", "schemes", "target_ids",
764 "init_regions", "kdamond_pid"};
765 const struct file_operations *fops[] = {&attrs_fops, &schemes_fops,
766 &target_ids_fops, &init_regions_fops, &kdamond_pid_fops};
767 int i;
768
769 for (i = 0; i < ARRAY_SIZE(file_names); i++)
770 debugfs_create_file(name: file_names[i], mode: 0600, parent: dir, data: ctx, fops: fops[i]);
771}
772
773static void dbgfs_before_terminate(struct damon_ctx *ctx)
774{
775 struct damon_target *t, *next;
776
777 if (!damon_target_has_pid(ctx))
778 return;
779
780 mutex_lock(&ctx->kdamond_lock);
781 damon_for_each_target_safe(t, next, ctx) {
782 put_pid(pid: t->pid);
783 damon_destroy_target(t);
784 }
785 mutex_unlock(lock: &ctx->kdamond_lock);
786}
787
788static struct damon_ctx *dbgfs_new_ctx(void)
789{
790 struct damon_ctx *ctx;
791
792 ctx = damon_new_ctx();
793 if (!ctx)
794 return NULL;
795
796 if (damon_select_ops(ctx, id: DAMON_OPS_VADDR) &&
797 damon_select_ops(ctx, id: DAMON_OPS_PADDR)) {
798 damon_destroy_ctx(ctx);
799 return NULL;
800 }
801 ctx->callback.before_terminate = dbgfs_before_terminate;
802 return ctx;
803}
804
805static void dbgfs_destroy_ctx(struct damon_ctx *ctx)
806{
807 damon_destroy_ctx(ctx);
808}
809
810static ssize_t damon_dbgfs_deprecated_read(struct file *file,
811 char __user *buf, size_t count, loff_t *ppos)
812{
813 static const char kbuf[512] = DAMON_DBGFS_DEPRECATION_NOTICE;
814
815 return simple_read_from_buffer(to: buf, count, ppos, from: kbuf, strlen(kbuf));
816}
817
818/*
819 * Make a context of @name and create a debugfs directory for it.
820 *
821 * This function should be called while holding damon_dbgfs_lock.
822 *
823 * Returns 0 on success, negative error code otherwise.
824 */
825static int dbgfs_mk_context(char *name)
826{
827 struct dentry *root, **new_dirs, *new_dir;
828 struct damon_ctx **new_ctxs, *new_ctx;
829
830 if (damon_nr_running_ctxs())
831 return -EBUSY;
832
833 new_ctxs = krealloc(objp: dbgfs_ctxs, new_size: sizeof(*dbgfs_ctxs) *
834 (dbgfs_nr_ctxs + 1), GFP_KERNEL);
835 if (!new_ctxs)
836 return -ENOMEM;
837 dbgfs_ctxs = new_ctxs;
838
839 new_dirs = krealloc(objp: dbgfs_dirs, new_size: sizeof(*dbgfs_dirs) *
840 (dbgfs_nr_ctxs + 1), GFP_KERNEL);
841 if (!new_dirs)
842 return -ENOMEM;
843 dbgfs_dirs = new_dirs;
844
845 root = dbgfs_dirs[0];
846 if (!root)
847 return -ENOENT;
848
849 new_dir = debugfs_create_dir(name, parent: root);
850 /* Below check is required for a potential duplicated name case */
851 if (IS_ERR(ptr: new_dir))
852 return PTR_ERR(ptr: new_dir);
853 dbgfs_dirs[dbgfs_nr_ctxs] = new_dir;
854
855 new_ctx = dbgfs_new_ctx();
856 if (!new_ctx) {
857 debugfs_remove(dentry: new_dir);
858 dbgfs_dirs[dbgfs_nr_ctxs] = NULL;
859 return -ENOMEM;
860 }
861
862 dbgfs_ctxs[dbgfs_nr_ctxs] = new_ctx;
863 dbgfs_fill_ctx_dir(dir: dbgfs_dirs[dbgfs_nr_ctxs],
864 ctx: dbgfs_ctxs[dbgfs_nr_ctxs]);
865 dbgfs_nr_ctxs++;
866
867 return 0;
868}
869
870static ssize_t dbgfs_mk_context_write(struct file *file,
871 const char __user *buf, size_t count, loff_t *ppos)
872{
873 char *kbuf;
874 char *ctx_name;
875 ssize_t ret;
876
877 kbuf = user_input_str(buf, count, ppos);
878 if (IS_ERR(ptr: kbuf))
879 return PTR_ERR(ptr: kbuf);
880 ctx_name = kmalloc(size: count + 1, GFP_KERNEL);
881 if (!ctx_name) {
882 kfree(objp: kbuf);
883 return -ENOMEM;
884 }
885
886 /* Trim white space */
887 if (sscanf(kbuf, "%s", ctx_name) != 1) {
888 ret = -EINVAL;
889 goto out;
890 }
891
892 mutex_lock(&damon_dbgfs_lock);
893 ret = dbgfs_mk_context(name: ctx_name);
894 if (!ret)
895 ret = count;
896 mutex_unlock(lock: &damon_dbgfs_lock);
897
898out:
899 kfree(objp: kbuf);
900 kfree(objp: ctx_name);
901 return ret;
902}
903
904/*
905 * Remove a context of @name and its debugfs directory.
906 *
907 * This function should be called while holding damon_dbgfs_lock.
908 *
909 * Return 0 on success, negative error code otherwise.
910 */
911static int dbgfs_rm_context(char *name)
912{
913 struct dentry *root, *dir, **new_dirs;
914 struct inode *inode;
915 struct damon_ctx **new_ctxs;
916 int i, j;
917 int ret = 0;
918
919 if (damon_nr_running_ctxs())
920 return -EBUSY;
921
922 root = dbgfs_dirs[0];
923 if (!root)
924 return -ENOENT;
925
926 dir = debugfs_lookup(name, parent: root);
927 if (!dir)
928 return -ENOENT;
929
930 inode = d_inode(dentry: dir);
931 if (!S_ISDIR(inode->i_mode)) {
932 ret = -EINVAL;
933 goto out_dput;
934 }
935
936 new_dirs = kmalloc_array(n: dbgfs_nr_ctxs - 1, size: sizeof(*dbgfs_dirs),
937 GFP_KERNEL);
938 if (!new_dirs) {
939 ret = -ENOMEM;
940 goto out_dput;
941 }
942
943 new_ctxs = kmalloc_array(n: dbgfs_nr_ctxs - 1, size: sizeof(*dbgfs_ctxs),
944 GFP_KERNEL);
945 if (!new_ctxs) {
946 ret = -ENOMEM;
947 goto out_new_dirs;
948 }
949
950 for (i = 0, j = 0; i < dbgfs_nr_ctxs; i++) {
951 if (dbgfs_dirs[i] == dir) {
952 debugfs_remove(dentry: dbgfs_dirs[i]);
953 dbgfs_destroy_ctx(ctx: dbgfs_ctxs[i]);
954 continue;
955 }
956 new_dirs[j] = dbgfs_dirs[i];
957 new_ctxs[j++] = dbgfs_ctxs[i];
958 }
959
960 kfree(objp: dbgfs_dirs);
961 kfree(objp: dbgfs_ctxs);
962
963 dbgfs_dirs = new_dirs;
964 dbgfs_ctxs = new_ctxs;
965 dbgfs_nr_ctxs--;
966
967 goto out_dput;
968
969out_new_dirs:
970 kfree(objp: new_dirs);
971out_dput:
972 dput(dir);
973 return ret;
974}
975
976static ssize_t dbgfs_rm_context_write(struct file *file,
977 const char __user *buf, size_t count, loff_t *ppos)
978{
979 char *kbuf;
980 ssize_t ret;
981 char *ctx_name;
982
983 kbuf = user_input_str(buf, count, ppos);
984 if (IS_ERR(ptr: kbuf))
985 return PTR_ERR(ptr: kbuf);
986 ctx_name = kmalloc(size: count + 1, GFP_KERNEL);
987 if (!ctx_name) {
988 kfree(objp: kbuf);
989 return -ENOMEM;
990 }
991
992 /* Trim white space */
993 if (sscanf(kbuf, "%s", ctx_name) != 1) {
994 ret = -EINVAL;
995 goto out;
996 }
997
998 mutex_lock(&damon_dbgfs_lock);
999 ret = dbgfs_rm_context(name: ctx_name);
1000 if (!ret)
1001 ret = count;
1002 mutex_unlock(lock: &damon_dbgfs_lock);
1003
1004out:
1005 kfree(objp: kbuf);
1006 kfree(objp: ctx_name);
1007 return ret;
1008}
1009
1010static ssize_t dbgfs_monitor_on_read(struct file *file,
1011 char __user *buf, size_t count, loff_t *ppos)
1012{
1013 char monitor_on_buf[5];
1014 bool monitor_on = damon_nr_running_ctxs() != 0;
1015 int len;
1016
1017 len = scnprintf(buf: monitor_on_buf, size: 5, fmt: monitor_on ? "on\n" : "off\n");
1018
1019 return simple_read_from_buffer(to: buf, count, ppos, from: monitor_on_buf, available: len);
1020}
1021
1022static ssize_t dbgfs_monitor_on_write(struct file *file,
1023 const char __user *buf, size_t count, loff_t *ppos)
1024{
1025 ssize_t ret;
1026 char *kbuf;
1027
1028 kbuf = user_input_str(buf, count, ppos);
1029 if (IS_ERR(ptr: kbuf))
1030 return PTR_ERR(ptr: kbuf);
1031
1032 /* Remove white space */
1033 if (sscanf(kbuf, "%s", kbuf) != 1) {
1034 kfree(objp: kbuf);
1035 return -EINVAL;
1036 }
1037
1038 mutex_lock(&damon_dbgfs_lock);
1039 if (!strncmp(kbuf, "on", count)) {
1040 int i;
1041
1042 for (i = 0; i < dbgfs_nr_ctxs; i++) {
1043 if (damon_targets_empty(ctx: dbgfs_ctxs[i])) {
1044 kfree(objp: kbuf);
1045 mutex_unlock(lock: &damon_dbgfs_lock);
1046 return -EINVAL;
1047 }
1048 }
1049 ret = damon_start(ctxs: dbgfs_ctxs, nr_ctxs: dbgfs_nr_ctxs, exclusive: true);
1050 } else if (!strncmp(kbuf, "off", count)) {
1051 ret = damon_stop(ctxs: dbgfs_ctxs, nr_ctxs: dbgfs_nr_ctxs);
1052 } else {
1053 ret = -EINVAL;
1054 }
1055 mutex_unlock(lock: &damon_dbgfs_lock);
1056
1057 if (!ret)
1058 ret = count;
1059 kfree(objp: kbuf);
1060 return ret;
1061}
1062
1063static int damon_dbgfs_static_file_open(struct inode *inode, struct file *file)
1064{
1065 damon_dbgfs_warn_deprecation();
1066 return nonseekable_open(inode, filp: file);
1067}
1068
1069static const struct file_operations deprecated_fops = {
1070 .read = damon_dbgfs_deprecated_read,
1071};
1072
1073static const struct file_operations mk_contexts_fops = {
1074 .open = damon_dbgfs_static_file_open,
1075 .write = dbgfs_mk_context_write,
1076};
1077
1078static const struct file_operations rm_contexts_fops = {
1079 .open = damon_dbgfs_static_file_open,
1080 .write = dbgfs_rm_context_write,
1081};
1082
1083static const struct file_operations monitor_on_fops = {
1084 .open = damon_dbgfs_static_file_open,
1085 .read = dbgfs_monitor_on_read,
1086 .write = dbgfs_monitor_on_write,
1087};
1088
1089static int __init __damon_dbgfs_init(void)
1090{
1091 struct dentry *dbgfs_root;
1092 const char * const file_names[] = {"mk_contexts", "rm_contexts",
1093 "monitor_on_DEPRECATED", "DEPRECATED"};
1094 const struct file_operations *fops[] = {&mk_contexts_fops,
1095 &rm_contexts_fops, &monitor_on_fops, &deprecated_fops};
1096 int i;
1097
1098 dbgfs_root = debugfs_create_dir(name: "damon", NULL);
1099
1100 for (i = 0; i < ARRAY_SIZE(file_names); i++)
1101 debugfs_create_file(name: file_names[i], mode: 0600, parent: dbgfs_root, NULL,
1102 fops: fops[i]);
1103 dbgfs_fill_ctx_dir(dir: dbgfs_root, ctx: dbgfs_ctxs[0]);
1104
1105 dbgfs_dirs = kmalloc(size: sizeof(dbgfs_root), GFP_KERNEL);
1106 if (!dbgfs_dirs) {
1107 debugfs_remove(dentry: dbgfs_root);
1108 return -ENOMEM;
1109 }
1110 dbgfs_dirs[0] = dbgfs_root;
1111
1112 return 0;
1113}
1114
1115/*
1116 * Functions for the initialization
1117 */
1118
1119static int __init damon_dbgfs_init(void)
1120{
1121 int rc = -ENOMEM;
1122
1123 mutex_lock(&damon_dbgfs_lock);
1124 dbgfs_ctxs = kmalloc(size: sizeof(*dbgfs_ctxs), GFP_KERNEL);
1125 if (!dbgfs_ctxs)
1126 goto out;
1127 dbgfs_ctxs[0] = dbgfs_new_ctx();
1128 if (!dbgfs_ctxs[0]) {
1129 kfree(objp: dbgfs_ctxs);
1130 goto out;
1131 }
1132 dbgfs_nr_ctxs = 1;
1133
1134 rc = __damon_dbgfs_init();
1135 if (rc) {
1136 kfree(objp: dbgfs_ctxs[0]);
1137 kfree(objp: dbgfs_ctxs);
1138 pr_err("%s: dbgfs init failed\n", __func__);
1139 }
1140
1141out:
1142 mutex_unlock(lock: &damon_dbgfs_lock);
1143 return rc;
1144}
1145
1146module_init(damon_dbgfs_init);
1147
1148#include "dbgfs-test.h"
1149

source code of linux/mm/damon/dbgfs.c