Docs/admin-guide/damon/reclaim: document 'skip_anon' parameter
[linux-block.git] / mm / damon / sysfs-schemes.c
CommitLineData
c8e7b4d0
SP
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * DAMON sysfs Interface
4 *
5 * Copyright (c) 2022 SeongJae Park <sj@kernel.org>
6 */
7
8#include <linux/slab.h>
9
10#include "sysfs-common.h"
11
9277d036
SP
12/*
13 * scheme region directory
14 */
15
16struct damon_sysfs_scheme_region {
17 struct kobject kobj;
18 struct damon_addr_range ar;
19 unsigned int nr_accesses;
20 unsigned int age;
21 struct list_head list;
22};
23
24static struct damon_sysfs_scheme_region *damon_sysfs_scheme_region_alloc(
25 struct damon_region *region)
26{
27 struct damon_sysfs_scheme_region *sysfs_region = kmalloc(
28 sizeof(*sysfs_region), GFP_KERNEL);
29
30 if (!sysfs_region)
31 return NULL;
32 sysfs_region->kobj = (struct kobject){};
33 sysfs_region->ar = region->ar;
34 sysfs_region->nr_accesses = region->nr_accesses;
35 sysfs_region->age = region->age;
36 INIT_LIST_HEAD(&sysfs_region->list);
37 return sysfs_region;
38}
39
40static ssize_t start_show(struct kobject *kobj, struct kobj_attribute *attr,
41 char *buf)
42{
43 struct damon_sysfs_scheme_region *region = container_of(kobj,
44 struct damon_sysfs_scheme_region, kobj);
45
46 return sysfs_emit(buf, "%lu\n", region->ar.start);
47}
48
49static ssize_t end_show(struct kobject *kobj, struct kobj_attribute *attr,
50 char *buf)
51{
52 struct damon_sysfs_scheme_region *region = container_of(kobj,
53 struct damon_sysfs_scheme_region, kobj);
54
55 return sysfs_emit(buf, "%lu\n", region->ar.end);
56}
57
58static ssize_t nr_accesses_show(struct kobject *kobj,
59 struct kobj_attribute *attr, char *buf)
60{
61 struct damon_sysfs_scheme_region *region = container_of(kobj,
62 struct damon_sysfs_scheme_region, kobj);
63
64 return sysfs_emit(buf, "%u\n", region->nr_accesses);
65}
66
67static ssize_t age_show(struct kobject *kobj, struct kobj_attribute *attr,
68 char *buf)
69{
70 struct damon_sysfs_scheme_region *region = container_of(kobj,
71 struct damon_sysfs_scheme_region, kobj);
72
73 return sysfs_emit(buf, "%u\n", region->age);
74}
75
76static void damon_sysfs_scheme_region_release(struct kobject *kobj)
77{
78 struct damon_sysfs_scheme_region *region = container_of(kobj,
79 struct damon_sysfs_scheme_region, kobj);
80
81 list_del(&region->list);
82 kfree(region);
83}
84
85static struct kobj_attribute damon_sysfs_scheme_region_start_attr =
86 __ATTR_RO_MODE(start, 0400);
87
88static struct kobj_attribute damon_sysfs_scheme_region_end_attr =
89 __ATTR_RO_MODE(end, 0400);
90
91static struct kobj_attribute damon_sysfs_scheme_region_nr_accesses_attr =
92 __ATTR_RO_MODE(nr_accesses, 0400);
93
94static struct kobj_attribute damon_sysfs_scheme_region_age_attr =
95 __ATTR_RO_MODE(age, 0400);
96
97static struct attribute *damon_sysfs_scheme_region_attrs[] = {
98 &damon_sysfs_scheme_region_start_attr.attr,
99 &damon_sysfs_scheme_region_end_attr.attr,
100 &damon_sysfs_scheme_region_nr_accesses_attr.attr,
101 &damon_sysfs_scheme_region_age_attr.attr,
102 NULL,
103};
104ATTRIBUTE_GROUPS(damon_sysfs_scheme_region);
105
106static struct kobj_type damon_sysfs_scheme_region_ktype = {
107 .release = damon_sysfs_scheme_region_release,
108 .sysfs_ops = &kobj_sysfs_ops,
109 .default_groups = damon_sysfs_scheme_region_groups,
110};
111
5181b75f
SP
112/*
113 * scheme regions directory
114 */
115
116struct damon_sysfs_scheme_regions {
117 struct kobject kobj;
9277d036
SP
118 struct list_head regions_list;
119 int nr_regions;
5181b75f
SP
120};
121
122static struct damon_sysfs_scheme_regions *
123damon_sysfs_scheme_regions_alloc(void)
124{
9277d036
SP
125 struct damon_sysfs_scheme_regions *regions = kmalloc(sizeof(*regions),
126 GFP_KERNEL);
127
128 regions->kobj = (struct kobject){};
129 INIT_LIST_HEAD(&regions->regions_list);
130 regions->nr_regions = 0;
131 return regions;
132}
133
134static void damon_sysfs_scheme_regions_rm_dirs(
135 struct damon_sysfs_scheme_regions *regions)
136{
137 struct damon_sysfs_scheme_region *r, *next;
138
139 list_for_each_entry_safe(r, next, &regions->regions_list, list) {
140 /* release function deletes it from the list */
141 kobject_put(&r->kobj);
142 regions->nr_regions--;
143 }
5181b75f
SP
144}
145
146static void damon_sysfs_scheme_regions_release(struct kobject *kobj)
147{
148 kfree(container_of(kobj, struct damon_sysfs_scheme_regions, kobj));
149}
150
151static struct attribute *damon_sysfs_scheme_regions_attrs[] = {
152 NULL,
153};
154ATTRIBUTE_GROUPS(damon_sysfs_scheme_regions);
155
156static struct kobj_type damon_sysfs_scheme_regions_ktype = {
157 .release = damon_sysfs_scheme_regions_release,
158 .sysfs_ops = &kobj_sysfs_ops,
159 .default_groups = damon_sysfs_scheme_regions_groups,
160};
161
c8e7b4d0
SP
162/*
163 * schemes/stats directory
164 */
165
166struct damon_sysfs_stats {
167 struct kobject kobj;
168 unsigned long nr_tried;
169 unsigned long sz_tried;
170 unsigned long nr_applied;
171 unsigned long sz_applied;
172 unsigned long qt_exceeds;
173};
174
175static struct damon_sysfs_stats *damon_sysfs_stats_alloc(void)
176{
177 return kzalloc(sizeof(struct damon_sysfs_stats), GFP_KERNEL);
178}
179
180static ssize_t nr_tried_show(struct kobject *kobj, struct kobj_attribute *attr,
181 char *buf)
182{
183 struct damon_sysfs_stats *stats = container_of(kobj,
184 struct damon_sysfs_stats, kobj);
185
186 return sysfs_emit(buf, "%lu\n", stats->nr_tried);
187}
188
189static ssize_t sz_tried_show(struct kobject *kobj, struct kobj_attribute *attr,
190 char *buf)
191{
192 struct damon_sysfs_stats *stats = container_of(kobj,
193 struct damon_sysfs_stats, kobj);
194
195 return sysfs_emit(buf, "%lu\n", stats->sz_tried);
196}
197
198static ssize_t nr_applied_show(struct kobject *kobj,
199 struct kobj_attribute *attr, char *buf)
200{
201 struct damon_sysfs_stats *stats = container_of(kobj,
202 struct damon_sysfs_stats, kobj);
203
204 return sysfs_emit(buf, "%lu\n", stats->nr_applied);
205}
206
207static ssize_t sz_applied_show(struct kobject *kobj,
208 struct kobj_attribute *attr, char *buf)
209{
210 struct damon_sysfs_stats *stats = container_of(kobj,
211 struct damon_sysfs_stats, kobj);
212
213 return sysfs_emit(buf, "%lu\n", stats->sz_applied);
214}
215
216static ssize_t qt_exceeds_show(struct kobject *kobj,
217 struct kobj_attribute *attr, char *buf)
218{
219 struct damon_sysfs_stats *stats = container_of(kobj,
220 struct damon_sysfs_stats, kobj);
221
222 return sysfs_emit(buf, "%lu\n", stats->qt_exceeds);
223}
224
225static void damon_sysfs_stats_release(struct kobject *kobj)
226{
227 kfree(container_of(kobj, struct damon_sysfs_stats, kobj));
228}
229
230static struct kobj_attribute damon_sysfs_stats_nr_tried_attr =
231 __ATTR_RO_MODE(nr_tried, 0400);
232
233static struct kobj_attribute damon_sysfs_stats_sz_tried_attr =
234 __ATTR_RO_MODE(sz_tried, 0400);
235
236static struct kobj_attribute damon_sysfs_stats_nr_applied_attr =
237 __ATTR_RO_MODE(nr_applied, 0400);
238
239static struct kobj_attribute damon_sysfs_stats_sz_applied_attr =
240 __ATTR_RO_MODE(sz_applied, 0400);
241
242static struct kobj_attribute damon_sysfs_stats_qt_exceeds_attr =
243 __ATTR_RO_MODE(qt_exceeds, 0400);
244
245static struct attribute *damon_sysfs_stats_attrs[] = {
246 &damon_sysfs_stats_nr_tried_attr.attr,
247 &damon_sysfs_stats_sz_tried_attr.attr,
248 &damon_sysfs_stats_nr_applied_attr.attr,
249 &damon_sysfs_stats_sz_applied_attr.attr,
250 &damon_sysfs_stats_qt_exceeds_attr.attr,
251 NULL,
252};
253ATTRIBUTE_GROUPS(damon_sysfs_stats);
254
255static struct kobj_type damon_sysfs_stats_ktype = {
256 .release = damon_sysfs_stats_release,
257 .sysfs_ops = &kobj_sysfs_ops,
258 .default_groups = damon_sysfs_stats_groups,
259};
260
261/*
262 * watermarks directory
263 */
264
265struct damon_sysfs_watermarks {
266 struct kobject kobj;
267 enum damos_wmark_metric metric;
268 unsigned long interval_us;
269 unsigned long high;
270 unsigned long mid;
271 unsigned long low;
272};
273
274static struct damon_sysfs_watermarks *damon_sysfs_watermarks_alloc(
275 enum damos_wmark_metric metric, unsigned long interval_us,
276 unsigned long high, unsigned long mid, unsigned long low)
277{
278 struct damon_sysfs_watermarks *watermarks = kmalloc(
279 sizeof(*watermarks), GFP_KERNEL);
280
281 if (!watermarks)
282 return NULL;
283 watermarks->kobj = (struct kobject){};
284 watermarks->metric = metric;
285 watermarks->interval_us = interval_us;
286 watermarks->high = high;
287 watermarks->mid = mid;
288 watermarks->low = low;
289 return watermarks;
290}
291
292/* Should match with enum damos_wmark_metric */
293static const char * const damon_sysfs_wmark_metric_strs[] = {
294 "none",
295 "free_mem_rate",
296};
297
298static ssize_t metric_show(struct kobject *kobj, struct kobj_attribute *attr,
299 char *buf)
300{
301 struct damon_sysfs_watermarks *watermarks = container_of(kobj,
302 struct damon_sysfs_watermarks, kobj);
303
304 return sysfs_emit(buf, "%s\n",
305 damon_sysfs_wmark_metric_strs[watermarks->metric]);
306}
307
308static ssize_t metric_store(struct kobject *kobj, struct kobj_attribute *attr,
309 const char *buf, size_t count)
310{
311 struct damon_sysfs_watermarks *watermarks = container_of(kobj,
312 struct damon_sysfs_watermarks, kobj);
313 enum damos_wmark_metric metric;
314
315 for (metric = 0; metric < NR_DAMOS_WMARK_METRICS; metric++) {
316 if (sysfs_streq(buf, damon_sysfs_wmark_metric_strs[metric])) {
317 watermarks->metric = metric;
318 return count;
319 }
320 }
321 return -EINVAL;
322}
323
324static ssize_t interval_us_show(struct kobject *kobj,
325 struct kobj_attribute *attr, char *buf)
326{
327 struct damon_sysfs_watermarks *watermarks = container_of(kobj,
328 struct damon_sysfs_watermarks, kobj);
329
330 return sysfs_emit(buf, "%lu\n", watermarks->interval_us);
331}
332
333static ssize_t interval_us_store(struct kobject *kobj,
334 struct kobj_attribute *attr, const char *buf, size_t count)
335{
336 struct damon_sysfs_watermarks *watermarks = container_of(kobj,
337 struct damon_sysfs_watermarks, kobj);
338 int err = kstrtoul(buf, 0, &watermarks->interval_us);
339
340 return err ? err : count;
341}
342
343static ssize_t high_show(struct kobject *kobj,
344 struct kobj_attribute *attr, char *buf)
345{
346 struct damon_sysfs_watermarks *watermarks = container_of(kobj,
347 struct damon_sysfs_watermarks, kobj);
348
349 return sysfs_emit(buf, "%lu\n", watermarks->high);
350}
351
352static ssize_t high_store(struct kobject *kobj,
353 struct kobj_attribute *attr, const char *buf, size_t count)
354{
355 struct damon_sysfs_watermarks *watermarks = container_of(kobj,
356 struct damon_sysfs_watermarks, kobj);
357 int err = kstrtoul(buf, 0, &watermarks->high);
358
359 return err ? err : count;
360}
361
362static ssize_t mid_show(struct kobject *kobj,
363 struct kobj_attribute *attr, char *buf)
364{
365 struct damon_sysfs_watermarks *watermarks = container_of(kobj,
366 struct damon_sysfs_watermarks, kobj);
367
368 return sysfs_emit(buf, "%lu\n", watermarks->mid);
369}
370
371static ssize_t mid_store(struct kobject *kobj,
372 struct kobj_attribute *attr, const char *buf, size_t count)
373{
374 struct damon_sysfs_watermarks *watermarks = container_of(kobj,
375 struct damon_sysfs_watermarks, kobj);
376 int err = kstrtoul(buf, 0, &watermarks->mid);
377
378 return err ? err : count;
379}
380
381static ssize_t low_show(struct kobject *kobj,
382 struct kobj_attribute *attr, char *buf)
383{
384 struct damon_sysfs_watermarks *watermarks = container_of(kobj,
385 struct damon_sysfs_watermarks, kobj);
386
387 return sysfs_emit(buf, "%lu\n", watermarks->low);
388}
389
390static ssize_t low_store(struct kobject *kobj,
391 struct kobj_attribute *attr, const char *buf, size_t count)
392{
393 struct damon_sysfs_watermarks *watermarks = container_of(kobj,
394 struct damon_sysfs_watermarks, kobj);
395 int err = kstrtoul(buf, 0, &watermarks->low);
396
397 return err ? err : count;
398}
399
400static void damon_sysfs_watermarks_release(struct kobject *kobj)
401{
402 kfree(container_of(kobj, struct damon_sysfs_watermarks, kobj));
403}
404
405static struct kobj_attribute damon_sysfs_watermarks_metric_attr =
406 __ATTR_RW_MODE(metric, 0600);
407
408static struct kobj_attribute damon_sysfs_watermarks_interval_us_attr =
409 __ATTR_RW_MODE(interval_us, 0600);
410
411static struct kobj_attribute damon_sysfs_watermarks_high_attr =
412 __ATTR_RW_MODE(high, 0600);
413
414static struct kobj_attribute damon_sysfs_watermarks_mid_attr =
415 __ATTR_RW_MODE(mid, 0600);
416
417static struct kobj_attribute damon_sysfs_watermarks_low_attr =
418 __ATTR_RW_MODE(low, 0600);
419
420static struct attribute *damon_sysfs_watermarks_attrs[] = {
421 &damon_sysfs_watermarks_metric_attr.attr,
422 &damon_sysfs_watermarks_interval_us_attr.attr,
423 &damon_sysfs_watermarks_high_attr.attr,
424 &damon_sysfs_watermarks_mid_attr.attr,
425 &damon_sysfs_watermarks_low_attr.attr,
426 NULL,
427};
428ATTRIBUTE_GROUPS(damon_sysfs_watermarks);
429
430static struct kobj_type damon_sysfs_watermarks_ktype = {
431 .release = damon_sysfs_watermarks_release,
432 .sysfs_ops = &kobj_sysfs_ops,
433 .default_groups = damon_sysfs_watermarks_groups,
434};
435
436/*
437 * scheme/weights directory
438 */
439
440struct damon_sysfs_weights {
441 struct kobject kobj;
442 unsigned int sz;
443 unsigned int nr_accesses;
444 unsigned int age;
445};
446
447static struct damon_sysfs_weights *damon_sysfs_weights_alloc(unsigned int sz,
448 unsigned int nr_accesses, unsigned int age)
449{
450 struct damon_sysfs_weights *weights = kmalloc(sizeof(*weights),
451 GFP_KERNEL);
452
453 if (!weights)
454 return NULL;
455 weights->kobj = (struct kobject){};
456 weights->sz = sz;
457 weights->nr_accesses = nr_accesses;
458 weights->age = age;
459 return weights;
460}
461
462static ssize_t sz_permil_show(struct kobject *kobj,
463 struct kobj_attribute *attr, char *buf)
464{
465 struct damon_sysfs_weights *weights = container_of(kobj,
466 struct damon_sysfs_weights, kobj);
467
468 return sysfs_emit(buf, "%u\n", weights->sz);
469}
470
471static ssize_t sz_permil_store(struct kobject *kobj,
472 struct kobj_attribute *attr, const char *buf, size_t count)
473{
474 struct damon_sysfs_weights *weights = container_of(kobj,
475 struct damon_sysfs_weights, kobj);
476 int err = kstrtouint(buf, 0, &weights->sz);
477
478 return err ? err : count;
479}
480
481static ssize_t nr_accesses_permil_show(struct kobject *kobj,
482 struct kobj_attribute *attr, char *buf)
483{
484 struct damon_sysfs_weights *weights = container_of(kobj,
485 struct damon_sysfs_weights, kobj);
486
487 return sysfs_emit(buf, "%u\n", weights->nr_accesses);
488}
489
490static ssize_t nr_accesses_permil_store(struct kobject *kobj,
491 struct kobj_attribute *attr, const char *buf, size_t count)
492{
493 struct damon_sysfs_weights *weights = container_of(kobj,
494 struct damon_sysfs_weights, kobj);
495 int err = kstrtouint(buf, 0, &weights->nr_accesses);
496
497 return err ? err : count;
498}
499
500static ssize_t age_permil_show(struct kobject *kobj,
501 struct kobj_attribute *attr, char *buf)
502{
503 struct damon_sysfs_weights *weights = container_of(kobj,
504 struct damon_sysfs_weights, kobj);
505
506 return sysfs_emit(buf, "%u\n", weights->age);
507}
508
509static ssize_t age_permil_store(struct kobject *kobj,
510 struct kobj_attribute *attr, const char *buf, size_t count)
511{
512 struct damon_sysfs_weights *weights = container_of(kobj,
513 struct damon_sysfs_weights, kobj);
514 int err = kstrtouint(buf, 0, &weights->age);
515
516 return err ? err : count;
517}
518
519static void damon_sysfs_weights_release(struct kobject *kobj)
520{
521 kfree(container_of(kobj, struct damon_sysfs_weights, kobj));
522}
523
524static struct kobj_attribute damon_sysfs_weights_sz_attr =
525 __ATTR_RW_MODE(sz_permil, 0600);
526
527static struct kobj_attribute damon_sysfs_weights_nr_accesses_attr =
528 __ATTR_RW_MODE(nr_accesses_permil, 0600);
529
530static struct kobj_attribute damon_sysfs_weights_age_attr =
531 __ATTR_RW_MODE(age_permil, 0600);
532
533static struct attribute *damon_sysfs_weights_attrs[] = {
534 &damon_sysfs_weights_sz_attr.attr,
535 &damon_sysfs_weights_nr_accesses_attr.attr,
536 &damon_sysfs_weights_age_attr.attr,
537 NULL,
538};
539ATTRIBUTE_GROUPS(damon_sysfs_weights);
540
541static struct kobj_type damon_sysfs_weights_ktype = {
542 .release = damon_sysfs_weights_release,
543 .sysfs_ops = &kobj_sysfs_ops,
544 .default_groups = damon_sysfs_weights_groups,
545};
546
547/*
548 * quotas directory
549 */
550
551struct damon_sysfs_quotas {
552 struct kobject kobj;
553 struct damon_sysfs_weights *weights;
554 unsigned long ms;
555 unsigned long sz;
556 unsigned long reset_interval_ms;
557};
558
559static struct damon_sysfs_quotas *damon_sysfs_quotas_alloc(void)
560{
561 return kzalloc(sizeof(struct damon_sysfs_quotas), GFP_KERNEL);
562}
563
564static int damon_sysfs_quotas_add_dirs(struct damon_sysfs_quotas *quotas)
565{
566 struct damon_sysfs_weights *weights;
567 int err;
568
569 weights = damon_sysfs_weights_alloc(0, 0, 0);
570 if (!weights)
571 return -ENOMEM;
572
573 err = kobject_init_and_add(&weights->kobj, &damon_sysfs_weights_ktype,
574 &quotas->kobj, "weights");
575 if (err)
576 kobject_put(&weights->kobj);
577 else
578 quotas->weights = weights;
579 return err;
580}
581
582static void damon_sysfs_quotas_rm_dirs(struct damon_sysfs_quotas *quotas)
583{
584 kobject_put(&quotas->weights->kobj);
585}
586
587static ssize_t ms_show(struct kobject *kobj, struct kobj_attribute *attr,
588 char *buf)
589{
590 struct damon_sysfs_quotas *quotas = container_of(kobj,
591 struct damon_sysfs_quotas, kobj);
592
593 return sysfs_emit(buf, "%lu\n", quotas->ms);
594}
595
596static ssize_t ms_store(struct kobject *kobj, struct kobj_attribute *attr,
597 const char *buf, size_t count)
598{
599 struct damon_sysfs_quotas *quotas = container_of(kobj,
600 struct damon_sysfs_quotas, kobj);
601 int err = kstrtoul(buf, 0, &quotas->ms);
602
603 if (err)
604 return -EINVAL;
605 return count;
606}
607
608static ssize_t bytes_show(struct kobject *kobj, struct kobj_attribute *attr,
609 char *buf)
610{
611 struct damon_sysfs_quotas *quotas = container_of(kobj,
612 struct damon_sysfs_quotas, kobj);
613
614 return sysfs_emit(buf, "%lu\n", quotas->sz);
615}
616
617static ssize_t bytes_store(struct kobject *kobj,
618 struct kobj_attribute *attr, const char *buf, size_t count)
619{
620 struct damon_sysfs_quotas *quotas = container_of(kobj,
621 struct damon_sysfs_quotas, kobj);
622 int err = kstrtoul(buf, 0, &quotas->sz);
623
624 if (err)
625 return -EINVAL;
626 return count;
627}
628
629static ssize_t reset_interval_ms_show(struct kobject *kobj,
630 struct kobj_attribute *attr, char *buf)
631{
632 struct damon_sysfs_quotas *quotas = container_of(kobj,
633 struct damon_sysfs_quotas, kobj);
634
635 return sysfs_emit(buf, "%lu\n", quotas->reset_interval_ms);
636}
637
638static ssize_t reset_interval_ms_store(struct kobject *kobj,
639 struct kobj_attribute *attr, const char *buf, size_t count)
640{
641 struct damon_sysfs_quotas *quotas = container_of(kobj,
642 struct damon_sysfs_quotas, kobj);
643 int err = kstrtoul(buf, 0, &quotas->reset_interval_ms);
644
645 if (err)
646 return -EINVAL;
647 return count;
648}
649
650static void damon_sysfs_quotas_release(struct kobject *kobj)
651{
652 kfree(container_of(kobj, struct damon_sysfs_quotas, kobj));
653}
654
655static struct kobj_attribute damon_sysfs_quotas_ms_attr =
656 __ATTR_RW_MODE(ms, 0600);
657
658static struct kobj_attribute damon_sysfs_quotas_sz_attr =
659 __ATTR_RW_MODE(bytes, 0600);
660
661static struct kobj_attribute damon_sysfs_quotas_reset_interval_ms_attr =
662 __ATTR_RW_MODE(reset_interval_ms, 0600);
663
664static struct attribute *damon_sysfs_quotas_attrs[] = {
665 &damon_sysfs_quotas_ms_attr.attr,
666 &damon_sysfs_quotas_sz_attr.attr,
667 &damon_sysfs_quotas_reset_interval_ms_attr.attr,
668 NULL,
669};
670ATTRIBUTE_GROUPS(damon_sysfs_quotas);
671
672static struct kobj_type damon_sysfs_quotas_ktype = {
673 .release = damon_sysfs_quotas_release,
674 .sysfs_ops = &kobj_sysfs_ops,
675 .default_groups = damon_sysfs_quotas_groups,
676};
677
678/*
679 * access_pattern directory
680 */
681
682struct damon_sysfs_access_pattern {
683 struct kobject kobj;
684 struct damon_sysfs_ul_range *sz;
685 struct damon_sysfs_ul_range *nr_accesses;
686 struct damon_sysfs_ul_range *age;
687};
688
689static
690struct damon_sysfs_access_pattern *damon_sysfs_access_pattern_alloc(void)
691{
692 struct damon_sysfs_access_pattern *access_pattern =
693 kmalloc(sizeof(*access_pattern), GFP_KERNEL);
694
695 if (!access_pattern)
696 return NULL;
697 access_pattern->kobj = (struct kobject){};
698 return access_pattern;
699}
700
701static int damon_sysfs_access_pattern_add_range_dir(
702 struct damon_sysfs_access_pattern *access_pattern,
703 struct damon_sysfs_ul_range **range_dir_ptr,
704 char *name)
705{
706 struct damon_sysfs_ul_range *range = damon_sysfs_ul_range_alloc(0, 0);
707 int err;
708
709 if (!range)
710 return -ENOMEM;
711 err = kobject_init_and_add(&range->kobj, &damon_sysfs_ul_range_ktype,
712 &access_pattern->kobj, name);
713 if (err)
714 kobject_put(&range->kobj);
715 else
716 *range_dir_ptr = range;
717 return err;
718}
719
720static int damon_sysfs_access_pattern_add_dirs(
721 struct damon_sysfs_access_pattern *access_pattern)
722{
723 int err;
724
725 err = damon_sysfs_access_pattern_add_range_dir(access_pattern,
726 &access_pattern->sz, "sz");
727 if (err)
728 goto put_sz_out;
729
730 err = damon_sysfs_access_pattern_add_range_dir(access_pattern,
731 &access_pattern->nr_accesses, "nr_accesses");
732 if (err)
733 goto put_nr_accesses_sz_out;
734
735 err = damon_sysfs_access_pattern_add_range_dir(access_pattern,
736 &access_pattern->age, "age");
737 if (err)
738 goto put_age_nr_accesses_sz_out;
739 return 0;
740
741put_age_nr_accesses_sz_out:
742 kobject_put(&access_pattern->age->kobj);
743 access_pattern->age = NULL;
744put_nr_accesses_sz_out:
745 kobject_put(&access_pattern->nr_accesses->kobj);
746 access_pattern->nr_accesses = NULL;
747put_sz_out:
748 kobject_put(&access_pattern->sz->kobj);
749 access_pattern->sz = NULL;
750 return err;
751}
752
753static void damon_sysfs_access_pattern_rm_dirs(
754 struct damon_sysfs_access_pattern *access_pattern)
755{
756 kobject_put(&access_pattern->sz->kobj);
757 kobject_put(&access_pattern->nr_accesses->kobj);
758 kobject_put(&access_pattern->age->kobj);
759}
760
761static void damon_sysfs_access_pattern_release(struct kobject *kobj)
762{
763 kfree(container_of(kobj, struct damon_sysfs_access_pattern, kobj));
764}
765
766static struct attribute *damon_sysfs_access_pattern_attrs[] = {
767 NULL,
768};
769ATTRIBUTE_GROUPS(damon_sysfs_access_pattern);
770
771static struct kobj_type damon_sysfs_access_pattern_ktype = {
772 .release = damon_sysfs_access_pattern_release,
773 .sysfs_ops = &kobj_sysfs_ops,
774 .default_groups = damon_sysfs_access_pattern_groups,
775};
776
777/*
778 * scheme directory
779 */
780
781struct damon_sysfs_scheme {
782 struct kobject kobj;
783 enum damos_action action;
784 struct damon_sysfs_access_pattern *access_pattern;
785 struct damon_sysfs_quotas *quotas;
786 struct damon_sysfs_watermarks *watermarks;
787 struct damon_sysfs_stats *stats;
5181b75f 788 struct damon_sysfs_scheme_regions *tried_regions;
c8e7b4d0
SP
789};
790
791/* This should match with enum damos_action */
792static const char * const damon_sysfs_damos_action_strs[] = {
793 "willneed",
794 "cold",
795 "pageout",
796 "hugepage",
797 "nohugepage",
798 "lru_prio",
799 "lru_deprio",
800 "stat",
801};
802
803static struct damon_sysfs_scheme *damon_sysfs_scheme_alloc(
804 enum damos_action action)
805{
806 struct damon_sysfs_scheme *scheme = kmalloc(sizeof(*scheme),
807 GFP_KERNEL);
808
809 if (!scheme)
810 return NULL;
811 scheme->kobj = (struct kobject){};
812 scheme->action = action;
813 return scheme;
814}
815
816static int damon_sysfs_scheme_set_access_pattern(
817 struct damon_sysfs_scheme *scheme)
818{
819 struct damon_sysfs_access_pattern *access_pattern;
820 int err;
821
822 access_pattern = damon_sysfs_access_pattern_alloc();
823 if (!access_pattern)
824 return -ENOMEM;
825 err = kobject_init_and_add(&access_pattern->kobj,
826 &damon_sysfs_access_pattern_ktype, &scheme->kobj,
827 "access_pattern");
828 if (err)
829 goto out;
830 err = damon_sysfs_access_pattern_add_dirs(access_pattern);
831 if (err)
832 goto out;
833 scheme->access_pattern = access_pattern;
834 return 0;
835
836out:
837 kobject_put(&access_pattern->kobj);
838 return err;
839}
840
841static int damon_sysfs_scheme_set_quotas(struct damon_sysfs_scheme *scheme)
842{
843 struct damon_sysfs_quotas *quotas = damon_sysfs_quotas_alloc();
844 int err;
845
846 if (!quotas)
847 return -ENOMEM;
848 err = kobject_init_and_add(&quotas->kobj, &damon_sysfs_quotas_ktype,
849 &scheme->kobj, "quotas");
850 if (err)
851 goto out;
852 err = damon_sysfs_quotas_add_dirs(quotas);
853 if (err)
854 goto out;
855 scheme->quotas = quotas;
856 return 0;
857
858out:
859 kobject_put(&quotas->kobj);
860 return err;
861}
862
863static int damon_sysfs_scheme_set_watermarks(struct damon_sysfs_scheme *scheme)
864{
865 struct damon_sysfs_watermarks *watermarks =
866 damon_sysfs_watermarks_alloc(DAMOS_WMARK_NONE, 0, 0, 0, 0);
867 int err;
868
869 if (!watermarks)
870 return -ENOMEM;
871 err = kobject_init_and_add(&watermarks->kobj,
872 &damon_sysfs_watermarks_ktype, &scheme->kobj,
873 "watermarks");
874 if (err)
875 kobject_put(&watermarks->kobj);
876 else
877 scheme->watermarks = watermarks;
878 return err;
879}
880
881static int damon_sysfs_scheme_set_stats(struct damon_sysfs_scheme *scheme)
882{
883 struct damon_sysfs_stats *stats = damon_sysfs_stats_alloc();
884 int err;
885
886 if (!stats)
887 return -ENOMEM;
888 err = kobject_init_and_add(&stats->kobj, &damon_sysfs_stats_ktype,
889 &scheme->kobj, "stats");
890 if (err)
891 kobject_put(&stats->kobj);
892 else
893 scheme->stats = stats;
894 return err;
895}
896
5181b75f
SP
897static int damon_sysfs_scheme_set_tried_regions(
898 struct damon_sysfs_scheme *scheme)
899{
900 struct damon_sysfs_scheme_regions *tried_regions =
901 damon_sysfs_scheme_regions_alloc();
902 int err;
903
904 if (!tried_regions)
905 return -ENOMEM;
906 err = kobject_init_and_add(&tried_regions->kobj,
907 &damon_sysfs_scheme_regions_ktype, &scheme->kobj,
908 "tried_regions");
909 if (err)
910 kobject_put(&tried_regions->kobj);
911 else
912 scheme->tried_regions = tried_regions;
913 return err;
914}
915
c8e7b4d0
SP
916static int damon_sysfs_scheme_add_dirs(struct damon_sysfs_scheme *scheme)
917{
918 int err;
919
920 err = damon_sysfs_scheme_set_access_pattern(scheme);
921 if (err)
922 return err;
923 err = damon_sysfs_scheme_set_quotas(scheme);
924 if (err)
925 goto put_access_pattern_out;
926 err = damon_sysfs_scheme_set_watermarks(scheme);
927 if (err)
928 goto put_quotas_access_pattern_out;
929 err = damon_sysfs_scheme_set_stats(scheme);
930 if (err)
931 goto put_watermarks_quotas_access_pattern_out;
5181b75f
SP
932 err = damon_sysfs_scheme_set_tried_regions(scheme);
933 if (err)
934 goto put_tried_regions_out;
c8e7b4d0
SP
935 return 0;
936
5181b75f
SP
937put_tried_regions_out:
938 kobject_put(&scheme->tried_regions->kobj);
939 scheme->tried_regions = NULL;
c8e7b4d0
SP
940put_watermarks_quotas_access_pattern_out:
941 kobject_put(&scheme->watermarks->kobj);
942 scheme->watermarks = NULL;
943put_quotas_access_pattern_out:
944 kobject_put(&scheme->quotas->kobj);
945 scheme->quotas = NULL;
946put_access_pattern_out:
947 kobject_put(&scheme->access_pattern->kobj);
948 scheme->access_pattern = NULL;
949 return err;
950}
951
952static void damon_sysfs_scheme_rm_dirs(struct damon_sysfs_scheme *scheme)
953{
954 damon_sysfs_access_pattern_rm_dirs(scheme->access_pattern);
955 kobject_put(&scheme->access_pattern->kobj);
956 damon_sysfs_quotas_rm_dirs(scheme->quotas);
957 kobject_put(&scheme->quotas->kobj);
958 kobject_put(&scheme->watermarks->kobj);
959 kobject_put(&scheme->stats->kobj);
9277d036 960 damon_sysfs_scheme_regions_rm_dirs(scheme->tried_regions);
5181b75f 961 kobject_put(&scheme->tried_regions->kobj);
c8e7b4d0
SP
962}
963
964static ssize_t action_show(struct kobject *kobj, struct kobj_attribute *attr,
965 char *buf)
966{
967 struct damon_sysfs_scheme *scheme = container_of(kobj,
968 struct damon_sysfs_scheme, kobj);
969
970 return sysfs_emit(buf, "%s\n",
971 damon_sysfs_damos_action_strs[scheme->action]);
972}
973
974static ssize_t action_store(struct kobject *kobj, struct kobj_attribute *attr,
975 const char *buf, size_t count)
976{
977 struct damon_sysfs_scheme *scheme = container_of(kobj,
978 struct damon_sysfs_scheme, kobj);
979 enum damos_action action;
980
981 for (action = 0; action < NR_DAMOS_ACTIONS; action++) {
982 if (sysfs_streq(buf, damon_sysfs_damos_action_strs[action])) {
983 scheme->action = action;
984 return count;
985 }
986 }
987 return -EINVAL;
988}
989
990static void damon_sysfs_scheme_release(struct kobject *kobj)
991{
992 kfree(container_of(kobj, struct damon_sysfs_scheme, kobj));
993}
994
995static struct kobj_attribute damon_sysfs_scheme_action_attr =
996 __ATTR_RW_MODE(action, 0600);
997
998static struct attribute *damon_sysfs_scheme_attrs[] = {
999 &damon_sysfs_scheme_action_attr.attr,
1000 NULL,
1001};
1002ATTRIBUTE_GROUPS(damon_sysfs_scheme);
1003
1004static struct kobj_type damon_sysfs_scheme_ktype = {
1005 .release = damon_sysfs_scheme_release,
1006 .sysfs_ops = &kobj_sysfs_ops,
1007 .default_groups = damon_sysfs_scheme_groups,
1008};
1009
1010/*
1011 * schemes directory
1012 */
1013
1014struct damon_sysfs_schemes *damon_sysfs_schemes_alloc(void)
1015{
1016 return kzalloc(sizeof(struct damon_sysfs_schemes), GFP_KERNEL);
1017}
1018
1019void damon_sysfs_schemes_rm_dirs(struct damon_sysfs_schemes *schemes)
1020{
1021 struct damon_sysfs_scheme **schemes_arr = schemes->schemes_arr;
1022 int i;
1023
1024 for (i = 0; i < schemes->nr; i++) {
1025 damon_sysfs_scheme_rm_dirs(schemes_arr[i]);
1026 kobject_put(&schemes_arr[i]->kobj);
1027 }
1028 schemes->nr = 0;
1029 kfree(schemes_arr);
1030 schemes->schemes_arr = NULL;
1031}
1032
1033static int damon_sysfs_schemes_add_dirs(struct damon_sysfs_schemes *schemes,
1034 int nr_schemes)
1035{
1036 struct damon_sysfs_scheme **schemes_arr, *scheme;
1037 int err, i;
1038
1039 damon_sysfs_schemes_rm_dirs(schemes);
1040 if (!nr_schemes)
1041 return 0;
1042
1043 schemes_arr = kmalloc_array(nr_schemes, sizeof(*schemes_arr),
1044 GFP_KERNEL | __GFP_NOWARN);
1045 if (!schemes_arr)
1046 return -ENOMEM;
1047 schemes->schemes_arr = schemes_arr;
1048
1049 for (i = 0; i < nr_schemes; i++) {
1050 scheme = damon_sysfs_scheme_alloc(DAMOS_STAT);
1051 if (!scheme) {
1052 damon_sysfs_schemes_rm_dirs(schemes);
1053 return -ENOMEM;
1054 }
1055
1056 err = kobject_init_and_add(&scheme->kobj,
1057 &damon_sysfs_scheme_ktype, &schemes->kobj,
1058 "%d", i);
1059 if (err)
1060 goto out;
1061 err = damon_sysfs_scheme_add_dirs(scheme);
1062 if (err)
1063 goto out;
1064
1065 schemes_arr[i] = scheme;
1066 schemes->nr++;
1067 }
1068 return 0;
1069
1070out:
1071 damon_sysfs_schemes_rm_dirs(schemes);
1072 kobject_put(&scheme->kobj);
1073 return err;
1074}
1075
1076static ssize_t nr_schemes_show(struct kobject *kobj,
1077 struct kobj_attribute *attr, char *buf)
1078{
1079 struct damon_sysfs_schemes *schemes = container_of(kobj,
1080 struct damon_sysfs_schemes, kobj);
1081
1082 return sysfs_emit(buf, "%d\n", schemes->nr);
1083}
1084
1085static ssize_t nr_schemes_store(struct kobject *kobj,
1086 struct kobj_attribute *attr, const char *buf, size_t count)
1087{
1088 struct damon_sysfs_schemes *schemes;
1089 int nr, err = kstrtoint(buf, 0, &nr);
1090
1091 if (err)
1092 return err;
1093 if (nr < 0)
1094 return -EINVAL;
1095
1096 schemes = container_of(kobj, struct damon_sysfs_schemes, kobj);
1097
1098 if (!mutex_trylock(&damon_sysfs_lock))
1099 return -EBUSY;
1100 err = damon_sysfs_schemes_add_dirs(schemes, nr);
1101 mutex_unlock(&damon_sysfs_lock);
1102 if (err)
1103 return err;
1104 return count;
1105}
1106
1107static void damon_sysfs_schemes_release(struct kobject *kobj)
1108{
1109 kfree(container_of(kobj, struct damon_sysfs_schemes, kobj));
1110}
1111
1112static struct kobj_attribute damon_sysfs_schemes_nr_attr =
1113 __ATTR_RW_MODE(nr_schemes, 0600);
1114
1115static struct attribute *damon_sysfs_schemes_attrs[] = {
1116 &damon_sysfs_schemes_nr_attr.attr,
1117 NULL,
1118};
1119ATTRIBUTE_GROUPS(damon_sysfs_schemes);
1120
1121struct kobj_type damon_sysfs_schemes_ktype = {
1122 .release = damon_sysfs_schemes_release,
1123 .sysfs_ops = &kobj_sysfs_ops,
1124 .default_groups = damon_sysfs_schemes_groups,
1125};
1126
1127static struct damos *damon_sysfs_mk_scheme(
1128 struct damon_sysfs_scheme *sysfs_scheme)
1129{
1130 struct damon_sysfs_access_pattern *access_pattern =
1131 sysfs_scheme->access_pattern;
1132 struct damon_sysfs_quotas *sysfs_quotas = sysfs_scheme->quotas;
1133 struct damon_sysfs_weights *sysfs_weights = sysfs_quotas->weights;
1134 struct damon_sysfs_watermarks *sysfs_wmarks = sysfs_scheme->watermarks;
1135
1136 struct damos_access_pattern pattern = {
1137 .min_sz_region = access_pattern->sz->min,
1138 .max_sz_region = access_pattern->sz->max,
1139 .min_nr_accesses = access_pattern->nr_accesses->min,
1140 .max_nr_accesses = access_pattern->nr_accesses->max,
1141 .min_age_region = access_pattern->age->min,
1142 .max_age_region = access_pattern->age->max,
1143 };
1144 struct damos_quota quota = {
1145 .ms = sysfs_quotas->ms,
1146 .sz = sysfs_quotas->sz,
1147 .reset_interval = sysfs_quotas->reset_interval_ms,
1148 .weight_sz = sysfs_weights->sz,
1149 .weight_nr_accesses = sysfs_weights->nr_accesses,
1150 .weight_age = sysfs_weights->age,
1151 };
1152 struct damos_watermarks wmarks = {
1153 .metric = sysfs_wmarks->metric,
1154 .interval = sysfs_wmarks->interval_us,
1155 .high = sysfs_wmarks->high,
1156 .mid = sysfs_wmarks->mid,
1157 .low = sysfs_wmarks->low,
1158 };
1159
1160 return damon_new_scheme(&pattern, sysfs_scheme->action, &quota,
1161 &wmarks);
1162}
1163
1164static void damon_sysfs_update_scheme(struct damos *scheme,
1165 struct damon_sysfs_scheme *sysfs_scheme)
1166{
1167 struct damon_sysfs_access_pattern *access_pattern =
1168 sysfs_scheme->access_pattern;
1169 struct damon_sysfs_quotas *sysfs_quotas = sysfs_scheme->quotas;
1170 struct damon_sysfs_weights *sysfs_weights = sysfs_quotas->weights;
1171 struct damon_sysfs_watermarks *sysfs_wmarks = sysfs_scheme->watermarks;
1172
1173 scheme->pattern.min_sz_region = access_pattern->sz->min;
1174 scheme->pattern.max_sz_region = access_pattern->sz->max;
1175 scheme->pattern.min_nr_accesses = access_pattern->nr_accesses->min;
1176 scheme->pattern.max_nr_accesses = access_pattern->nr_accesses->max;
1177 scheme->pattern.min_age_region = access_pattern->age->min;
1178 scheme->pattern.max_age_region = access_pattern->age->max;
1179
1180 scheme->action = sysfs_scheme->action;
1181
1182 scheme->quota.ms = sysfs_quotas->ms;
1183 scheme->quota.sz = sysfs_quotas->sz;
1184 scheme->quota.reset_interval = sysfs_quotas->reset_interval_ms;
1185 scheme->quota.weight_sz = sysfs_weights->sz;
1186 scheme->quota.weight_nr_accesses = sysfs_weights->nr_accesses;
1187 scheme->quota.weight_age = sysfs_weights->age;
1188
1189 scheme->wmarks.metric = sysfs_wmarks->metric;
1190 scheme->wmarks.interval = sysfs_wmarks->interval_us;
1191 scheme->wmarks.high = sysfs_wmarks->high;
1192 scheme->wmarks.mid = sysfs_wmarks->mid;
1193 scheme->wmarks.low = sysfs_wmarks->low;
1194}
1195
1196int damon_sysfs_set_schemes(struct damon_ctx *ctx,
1197 struct damon_sysfs_schemes *sysfs_schemes)
1198{
1199 struct damos *scheme, *next;
1200 int i = 0;
1201
1202 damon_for_each_scheme_safe(scheme, next, ctx) {
1203 if (i < sysfs_schemes->nr)
1204 damon_sysfs_update_scheme(scheme,
1205 sysfs_schemes->schemes_arr[i]);
1206 else
1207 damon_destroy_scheme(scheme);
1208 i++;
1209 }
1210
1211 for (; i < sysfs_schemes->nr; i++) {
1212 struct damos *scheme, *next;
1213
1214 scheme = damon_sysfs_mk_scheme(sysfs_schemes->schemes_arr[i]);
1215 if (!scheme) {
1216 damon_for_each_scheme_safe(scheme, next, ctx)
1217 damon_destroy_scheme(scheme);
1218 return -ENOMEM;
1219 }
1220 damon_add_scheme(ctx, scheme);
1221 }
1222 return 0;
1223}
1224
1225void damon_sysfs_schemes_update_stats(
1226 struct damon_sysfs_schemes *sysfs_schemes,
1227 struct damon_ctx *ctx)
1228{
1229 struct damos *scheme;
1230 int schemes_idx = 0;
1231
1232 damon_for_each_scheme(scheme, ctx) {
1233 struct damon_sysfs_stats *sysfs_stats;
1234
1235 /* user could have removed the scheme sysfs dir */
1236 if (schemes_idx >= sysfs_schemes->nr)
1237 break;
1238
1239 sysfs_stats = sysfs_schemes->schemes_arr[schemes_idx++]->stats;
1240 sysfs_stats->nr_tried = scheme->stat.nr_tried;
1241 sysfs_stats->sz_tried = scheme->stat.sz_tried;
1242 sysfs_stats->nr_applied = scheme->stat.nr_applied;
1243 sysfs_stats->sz_applied = scheme->stat.sz_applied;
1244 sysfs_stats->qt_exceeds = scheme->stat.qt_exceeds;
1245 }
1246}
f1d13cac
SP
1247
1248/*
1249 * damon_sysfs_schemes that need to update its schemes regions dir. Protected
1250 * by damon_sysfs_lock
1251 */
1252static struct damon_sysfs_schemes *damon_sysfs_schemes_for_damos_callback;
1253static int damon_sysfs_schemes_region_idx;
1254
1255/*
1256 * DAMON callback that called before damos apply. While this callback is
1257 * registered, damon_sysfs_lock should be held to ensure the regions
1258 * directories exist.
1259 */
1260static int damon_sysfs_before_damos_apply(struct damon_ctx *ctx,
1261 struct damon_target *t, struct damon_region *r,
1262 struct damos *s)
1263{
1264 struct damos *scheme;
1265 struct damon_sysfs_scheme_regions *sysfs_regions;
1266 struct damon_sysfs_scheme_region *region;
1267 struct damon_sysfs_schemes *sysfs_schemes =
1268 damon_sysfs_schemes_for_damos_callback;
1269 int schemes_idx = 0;
1270
1271 damon_for_each_scheme(scheme, ctx) {
1272 if (scheme == s)
1273 break;
1274 schemes_idx++;
1275 }
1276
1277 /* user could have removed the scheme sysfs dir */
1278 if (schemes_idx >= sysfs_schemes->nr)
1279 return 0;
1280
1281 sysfs_regions = sysfs_schemes->schemes_arr[schemes_idx]->tried_regions;
1282 region = damon_sysfs_scheme_region_alloc(r);
1283 list_add_tail(&region->list, &sysfs_regions->regions_list);
1284 sysfs_regions->nr_regions++;
1285 if (kobject_init_and_add(&region->kobj,
1286 &damon_sysfs_scheme_region_ktype,
1287 &sysfs_regions->kobj, "%d",
1288 damon_sysfs_schemes_region_idx++)) {
1289 kobject_put(&region->kobj);
1290 }
1291 return 0;
1292}
1293
1294/* Called from damon_sysfs_cmd_request_callback under damon_sysfs_lock */
772c15e5 1295int damon_sysfs_schemes_clear_regions(
f1d13cac
SP
1296 struct damon_sysfs_schemes *sysfs_schemes,
1297 struct damon_ctx *ctx)
1298{
1299 struct damos *scheme;
1300 int schemes_idx = 0;
1301
1302 damon_for_each_scheme(scheme, ctx) {
1303 struct damon_sysfs_scheme *sysfs_scheme;
1304
772c15e5
SP
1305 /* user could have removed the scheme sysfs dir */
1306 if (schemes_idx >= sysfs_schemes->nr)
1307 break;
1308
f1d13cac
SP
1309 sysfs_scheme = sysfs_schemes->schemes_arr[schemes_idx++];
1310 damon_sysfs_scheme_regions_rm_dirs(
1311 sysfs_scheme->tried_regions);
1312 }
772c15e5
SP
1313 return 0;
1314}
f1d13cac 1315
772c15e5
SP
1316/* Called from damon_sysfs_cmd_request_callback under damon_sysfs_lock */
1317int damon_sysfs_schemes_update_regions_start(
1318 struct damon_sysfs_schemes *sysfs_schemes,
1319 struct damon_ctx *ctx)
1320{
1321 damon_sysfs_schemes_clear_regions(sysfs_schemes, ctx);
f1d13cac
SP
1322 damon_sysfs_schemes_for_damos_callback = sysfs_schemes;
1323 ctx->callback.before_damos_apply = damon_sysfs_before_damos_apply;
1324 return 0;
1325}
1326
1327/*
1328 * Called from damon_sysfs_cmd_request_callback under damon_sysfs_lock. Caller
1329 * should unlock damon_sysfs_lock which held before
1330 * damon_sysfs_schemes_update_regions_start()
1331 */
1332int damon_sysfs_schemes_update_regions_stop(struct damon_ctx *ctx)
1333{
1334 damon_sysfs_schemes_for_damos_callback = NULL;
1335 ctx->callback.before_damos_apply = NULL;
1336 damon_sysfs_schemes_region_idx = 0;
1337 return 0;
1338}