mm/damon/sysfs: check error from damon_sysfs_update_target()
[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;
e7639bb4 34 sysfs_region->nr_accesses = region->nr_accesses_bp / 10000;
9277d036
SP
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
e56397e8 106static const struct kobj_type damon_sysfs_scheme_region_ktype = {
9277d036
SP
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
4d4e41b6
SP
116/*
117 * enum damos_sysfs_regions_upd_status - Represent DAMOS tried regions update
118 * status
119 * @DAMOS_TRIED_REGIONS_UPD_IDLE: Waiting for next request.
120 * @DAMOS_TRIED_REGIONS_UPD_STARTED: Update started.
121 * @DAMOS_TRIED_REGIONS_UPD_FINISHED: Update finished.
122 *
123 * Each DAMON-based operation scheme (&struct damos) has its own apply
124 * interval, and we need to expose the scheme tried regions based on only
125 * single snapshot. For this, we keep the tried regions update status for each
126 * scheme. The status becomes 'idle' at the beginning.
127 *
128 * Once the tried regions update request is received, the request handling
129 * start function (damon_sysfs_scheme_update_regions_start()) sets the status
130 * of all schemes as 'idle' again, and register ->before_damos_apply() and
131 * ->after_sampling() callbacks.
132 *
133 * Then, the first followup ->before_damos_apply() callback
134 * (damon_sysfs_before_damos_apply()) sets the status 'started'. The first
135 * ->after_sampling() callback (damon_sysfs_after_sampling()) after the call
136 * is called only after the scheme is completely applied
137 * to the given snapshot. Hence the callback knows the situation by showing
138 * 'started' status, and sets the status as 'finished'. Then,
139 * damon_sysfs_before_damos_apply() understands the situation by showing the
140 * 'finished' status and do nothing.
141 *
142 * Finally, the tried regions request handling finisher function
143 * (damon_sysfs_schemes_update_regions_stop()) unregisters the callbacks.
144 */
145enum damos_sysfs_regions_upd_status {
146 DAMOS_TRIED_REGIONS_UPD_IDLE,
147 DAMOS_TRIED_REGIONS_UPD_STARTED,
148 DAMOS_TRIED_REGIONS_UPD_FINISHED,
149};
150
5181b75f
SP
151struct damon_sysfs_scheme_regions {
152 struct kobject kobj;
9277d036
SP
153 struct list_head regions_list;
154 int nr_regions;
b69f92a7 155 unsigned long total_bytes;
4d4e41b6 156 enum damos_sysfs_regions_upd_status upd_status;
5181b75f
SP
157};
158
159static struct damon_sysfs_scheme_regions *
160damon_sysfs_scheme_regions_alloc(void)
161{
9277d036
SP
162 struct damon_sysfs_scheme_regions *regions = kmalloc(sizeof(*regions),
163 GFP_KERNEL);
164
165 regions->kobj = (struct kobject){};
166 INIT_LIST_HEAD(&regions->regions_list);
167 regions->nr_regions = 0;
b69f92a7 168 regions->total_bytes = 0;
4d4e41b6 169 regions->upd_status = DAMOS_TRIED_REGIONS_UPD_IDLE;
9277d036
SP
170 return regions;
171}
172
b69f92a7
SP
173static ssize_t total_bytes_show(struct kobject *kobj,
174 struct kobj_attribute *attr, char *buf)
175{
176 struct damon_sysfs_scheme_regions *regions = container_of(kobj,
177 struct damon_sysfs_scheme_regions, kobj);
178
179 return sysfs_emit(buf, "%lu\n", regions->total_bytes);
180}
181
9277d036
SP
182static void damon_sysfs_scheme_regions_rm_dirs(
183 struct damon_sysfs_scheme_regions *regions)
184{
185 struct damon_sysfs_scheme_region *r, *next;
186
187 list_for_each_entry_safe(r, next, &regions->regions_list, list) {
188 /* release function deletes it from the list */
189 kobject_put(&r->kobj);
190 regions->nr_regions--;
191 }
5181b75f
SP
192}
193
194static void damon_sysfs_scheme_regions_release(struct kobject *kobj)
195{
196 kfree(container_of(kobj, struct damon_sysfs_scheme_regions, kobj));
197}
198
b69f92a7
SP
199static struct kobj_attribute damon_sysfs_scheme_regions_total_bytes_attr =
200 __ATTR_RO_MODE(total_bytes, 0400);
201
5181b75f 202static struct attribute *damon_sysfs_scheme_regions_attrs[] = {
b69f92a7 203 &damon_sysfs_scheme_regions_total_bytes_attr.attr,
5181b75f
SP
204 NULL,
205};
206ATTRIBUTE_GROUPS(damon_sysfs_scheme_regions);
207
e56397e8 208static const struct kobj_type damon_sysfs_scheme_regions_ktype = {
5181b75f
SP
209 .release = damon_sysfs_scheme_regions_release,
210 .sysfs_ops = &kobj_sysfs_ops,
211 .default_groups = damon_sysfs_scheme_regions_groups,
212};
213
c8e7b4d0
SP
214/*
215 * schemes/stats directory
216 */
217
218struct damon_sysfs_stats {
219 struct kobject kobj;
220 unsigned long nr_tried;
221 unsigned long sz_tried;
222 unsigned long nr_applied;
223 unsigned long sz_applied;
224 unsigned long qt_exceeds;
225};
226
227static struct damon_sysfs_stats *damon_sysfs_stats_alloc(void)
228{
229 return kzalloc(sizeof(struct damon_sysfs_stats), GFP_KERNEL);
230}
231
232static ssize_t nr_tried_show(struct kobject *kobj, struct kobj_attribute *attr,
233 char *buf)
234{
235 struct damon_sysfs_stats *stats = container_of(kobj,
236 struct damon_sysfs_stats, kobj);
237
238 return sysfs_emit(buf, "%lu\n", stats->nr_tried);
239}
240
241static ssize_t sz_tried_show(struct kobject *kobj, struct kobj_attribute *attr,
242 char *buf)
243{
244 struct damon_sysfs_stats *stats = container_of(kobj,
245 struct damon_sysfs_stats, kobj);
246
247 return sysfs_emit(buf, "%lu\n", stats->sz_tried);
248}
249
250static ssize_t nr_applied_show(struct kobject *kobj,
251 struct kobj_attribute *attr, char *buf)
252{
253 struct damon_sysfs_stats *stats = container_of(kobj,
254 struct damon_sysfs_stats, kobj);
255
256 return sysfs_emit(buf, "%lu\n", stats->nr_applied);
257}
258
259static ssize_t sz_applied_show(struct kobject *kobj,
260 struct kobj_attribute *attr, char *buf)
261{
262 struct damon_sysfs_stats *stats = container_of(kobj,
263 struct damon_sysfs_stats, kobj);
264
265 return sysfs_emit(buf, "%lu\n", stats->sz_applied);
266}
267
268static ssize_t qt_exceeds_show(struct kobject *kobj,
269 struct kobj_attribute *attr, char *buf)
270{
271 struct damon_sysfs_stats *stats = container_of(kobj,
272 struct damon_sysfs_stats, kobj);
273
274 return sysfs_emit(buf, "%lu\n", stats->qt_exceeds);
275}
276
277static void damon_sysfs_stats_release(struct kobject *kobj)
278{
279 kfree(container_of(kobj, struct damon_sysfs_stats, kobj));
280}
281
282static struct kobj_attribute damon_sysfs_stats_nr_tried_attr =
283 __ATTR_RO_MODE(nr_tried, 0400);
284
285static struct kobj_attribute damon_sysfs_stats_sz_tried_attr =
286 __ATTR_RO_MODE(sz_tried, 0400);
287
288static struct kobj_attribute damon_sysfs_stats_nr_applied_attr =
289 __ATTR_RO_MODE(nr_applied, 0400);
290
291static struct kobj_attribute damon_sysfs_stats_sz_applied_attr =
292 __ATTR_RO_MODE(sz_applied, 0400);
293
294static struct kobj_attribute damon_sysfs_stats_qt_exceeds_attr =
295 __ATTR_RO_MODE(qt_exceeds, 0400);
296
297static struct attribute *damon_sysfs_stats_attrs[] = {
298 &damon_sysfs_stats_nr_tried_attr.attr,
299 &damon_sysfs_stats_sz_tried_attr.attr,
300 &damon_sysfs_stats_nr_applied_attr.attr,
301 &damon_sysfs_stats_sz_applied_attr.attr,
302 &damon_sysfs_stats_qt_exceeds_attr.attr,
303 NULL,
304};
305ATTRIBUTE_GROUPS(damon_sysfs_stats);
306
e56397e8 307static const struct kobj_type damon_sysfs_stats_ktype = {
c8e7b4d0
SP
308 .release = damon_sysfs_stats_release,
309 .sysfs_ops = &kobj_sysfs_ops,
310 .default_groups = damon_sysfs_stats_groups,
311};
312
7ee161f1
SP
313/*
314 * filter directory
315 */
316
317struct damon_sysfs_scheme_filter {
318 struct kobject kobj;
319 enum damos_filter_type type;
320 bool matching;
321 char *memcg_path;
2f1abcfc 322 struct damon_addr_range addr_range;
9f6e47ab 323 int target_idx;
7ee161f1
SP
324};
325
472e2b70
SP
326static struct damon_sysfs_scheme_filter *damon_sysfs_scheme_filter_alloc(void)
327{
328 return kzalloc(sizeof(struct damon_sysfs_scheme_filter), GFP_KERNEL);
329}
330
7ee161f1
SP
331/* Should match with enum damos_filter_type */
332static const char * const damon_sysfs_scheme_filter_type_strs[] = {
333 "anon",
334 "memcg",
2f1abcfc 335 "addr",
9f6e47ab 336 "target",
7ee161f1
SP
337};
338
339static ssize_t type_show(struct kobject *kobj,
340 struct kobj_attribute *attr, char *buf)
341{
342 struct damon_sysfs_scheme_filter *filter = container_of(kobj,
343 struct damon_sysfs_scheme_filter, kobj);
344
345 return sysfs_emit(buf, "%s\n",
346 damon_sysfs_scheme_filter_type_strs[filter->type]);
347}
348
349static ssize_t type_store(struct kobject *kobj,
350 struct kobj_attribute *attr, const char *buf, size_t count)
351{
352 struct damon_sysfs_scheme_filter *filter = container_of(kobj,
353 struct damon_sysfs_scheme_filter, kobj);
354 enum damos_filter_type type;
355 ssize_t ret = -EINVAL;
356
357 for (type = 0; type < NR_DAMOS_FILTER_TYPES; type++) {
358 if (sysfs_streq(buf, damon_sysfs_scheme_filter_type_strs[
359 type])) {
360 filter->type = type;
361 ret = count;
362 break;
363 }
364 }
365 return ret;
366}
367
368static ssize_t matching_show(struct kobject *kobj,
369 struct kobj_attribute *attr, char *buf)
370{
371 struct damon_sysfs_scheme_filter *filter = container_of(kobj,
372 struct damon_sysfs_scheme_filter, kobj);
373
374 return sysfs_emit(buf, "%c\n", filter->matching ? 'Y' : 'N');
375}
376
377static ssize_t matching_store(struct kobject *kobj,
378 struct kobj_attribute *attr, const char *buf, size_t count)
379{
380 struct damon_sysfs_scheme_filter *filter = container_of(kobj,
381 struct damon_sysfs_scheme_filter, kobj);
382 bool matching;
383 int err = kstrtobool(buf, &matching);
384
385 if (err)
386 return err;
387
388 filter->matching = matching;
389 return count;
390}
391
392static ssize_t memcg_path_show(struct kobject *kobj,
393 struct kobj_attribute *attr, char *buf)
394{
395 struct damon_sysfs_scheme_filter *filter = container_of(kobj,
396 struct damon_sysfs_scheme_filter, kobj);
397
398 return sysfs_emit(buf, "%s\n",
399 filter->memcg_path ? filter->memcg_path : "");
400}
401
402static ssize_t memcg_path_store(struct kobject *kobj,
403 struct kobj_attribute *attr, const char *buf, size_t count)
404{
405 struct damon_sysfs_scheme_filter *filter = container_of(kobj,
406 struct damon_sysfs_scheme_filter, kobj);
407 char *path = kmalloc(sizeof(*path) * (count + 1), GFP_KERNEL);
408
409 if (!path)
410 return -ENOMEM;
411
b6f00c91 412 strscpy(path, buf, count + 1);
7ee161f1
SP
413 filter->memcg_path = path;
414 return count;
415}
416
2f1abcfc
SP
417static ssize_t addr_start_show(struct kobject *kobj,
418 struct kobj_attribute *attr, char *buf)
419{
420 struct damon_sysfs_scheme_filter *filter = container_of(kobj,
421 struct damon_sysfs_scheme_filter, kobj);
422
423 return sysfs_emit(buf, "%lu\n", filter->addr_range.start);
424}
425
426static ssize_t addr_start_store(struct kobject *kobj,
427 struct kobj_attribute *attr, const char *buf, size_t count)
428{
429 struct damon_sysfs_scheme_filter *filter = container_of(kobj,
430 struct damon_sysfs_scheme_filter, kobj);
431 int err = kstrtoul(buf, 0, &filter->addr_range.start);
432
433 return err ? err : count;
434}
435
436static ssize_t addr_end_show(struct kobject *kobj,
437 struct kobj_attribute *attr, char *buf)
438{
439 struct damon_sysfs_scheme_filter *filter = container_of(kobj,
440 struct damon_sysfs_scheme_filter, kobj);
441
442 return sysfs_emit(buf, "%lu\n", filter->addr_range.end);
443}
444
445static ssize_t addr_end_store(struct kobject *kobj,
446 struct kobj_attribute *attr, const char *buf, size_t count)
447{
448 struct damon_sysfs_scheme_filter *filter = container_of(kobj,
449 struct damon_sysfs_scheme_filter, kobj);
450 int err = kstrtoul(buf, 0, &filter->addr_range.end);
451
452 return err ? err : count;
453}
454
9f6e47ab
SP
455static ssize_t damon_target_idx_show(struct kobject *kobj,
456 struct kobj_attribute *attr, char *buf)
457{
458 struct damon_sysfs_scheme_filter *filter = container_of(kobj,
459 struct damon_sysfs_scheme_filter, kobj);
460
461 return sysfs_emit(buf, "%d\n", filter->target_idx);
462}
463
464static ssize_t damon_target_idx_store(struct kobject *kobj,
465 struct kobj_attribute *attr, const char *buf, size_t count)
466{
467 struct damon_sysfs_scheme_filter *filter = container_of(kobj,
468 struct damon_sysfs_scheme_filter, kobj);
469 int err = kstrtoint(buf, 0, &filter->target_idx);
470
471 return err ? err : count;
472}
473
7ee161f1
SP
474static void damon_sysfs_scheme_filter_release(struct kobject *kobj)
475{
476 struct damon_sysfs_scheme_filter *filter = container_of(kobj,
477 struct damon_sysfs_scheme_filter, kobj);
478
479 kfree(filter->memcg_path);
480 kfree(filter);
481}
482
483static struct kobj_attribute damon_sysfs_scheme_filter_type_attr =
484 __ATTR_RW_MODE(type, 0600);
485
486static struct kobj_attribute damon_sysfs_scheme_filter_matching_attr =
487 __ATTR_RW_MODE(matching, 0600);
488
489static struct kobj_attribute damon_sysfs_scheme_filter_memcg_path_attr =
490 __ATTR_RW_MODE(memcg_path, 0600);
491
2f1abcfc
SP
492static struct kobj_attribute damon_sysfs_scheme_filter_addr_start_attr =
493 __ATTR_RW_MODE(addr_start, 0600);
494
495static struct kobj_attribute damon_sysfs_scheme_filter_addr_end_attr =
496 __ATTR_RW_MODE(addr_end, 0600);
497
9f6e47ab
SP
498static struct kobj_attribute damon_sysfs_scheme_filter_damon_target_idx_attr =
499 __ATTR_RW_MODE(damon_target_idx, 0600);
500
7ee161f1
SP
501static struct attribute *damon_sysfs_scheme_filter_attrs[] = {
502 &damon_sysfs_scheme_filter_type_attr.attr,
503 &damon_sysfs_scheme_filter_matching_attr.attr,
504 &damon_sysfs_scheme_filter_memcg_path_attr.attr,
2f1abcfc
SP
505 &damon_sysfs_scheme_filter_addr_start_attr.attr,
506 &damon_sysfs_scheme_filter_addr_end_attr.attr,
9f6e47ab 507 &damon_sysfs_scheme_filter_damon_target_idx_attr.attr,
7ee161f1
SP
508 NULL,
509};
510ATTRIBUTE_GROUPS(damon_sysfs_scheme_filter);
511
02cd4eb8 512static const struct kobj_type damon_sysfs_scheme_filter_ktype = {
7ee161f1
SP
513 .release = damon_sysfs_scheme_filter_release,
514 .sysfs_ops = &kobj_sysfs_ops,
515 .default_groups = damon_sysfs_scheme_filter_groups,
516};
517
ac35264b
SP
518/*
519 * filters directory
520 */
521
522struct damon_sysfs_scheme_filters {
523 struct kobject kobj;
472e2b70 524 struct damon_sysfs_scheme_filter **filters_arr;
ac35264b
SP
525 int nr;
526};
527
528static struct damon_sysfs_scheme_filters *
529damon_sysfs_scheme_filters_alloc(void)
530{
531 return kzalloc(sizeof(struct damon_sysfs_scheme_filters), GFP_KERNEL);
532}
533
472e2b70
SP
534static void damon_sysfs_scheme_filters_rm_dirs(
535 struct damon_sysfs_scheme_filters *filters)
536{
537 struct damon_sysfs_scheme_filter **filters_arr = filters->filters_arr;
538 int i;
539
540 for (i = 0; i < filters->nr; i++)
541 kobject_put(&filters_arr[i]->kobj);
542 filters->nr = 0;
543 kfree(filters_arr);
544 filters->filters_arr = NULL;
545}
546
547static int damon_sysfs_scheme_filters_add_dirs(
548 struct damon_sysfs_scheme_filters *filters, int nr_filters)
549{
550 struct damon_sysfs_scheme_filter **filters_arr, *filter;
551 int err, i;
552
553 damon_sysfs_scheme_filters_rm_dirs(filters);
554 if (!nr_filters)
555 return 0;
556
557 filters_arr = kmalloc_array(nr_filters, sizeof(*filters_arr),
558 GFP_KERNEL | __GFP_NOWARN);
559 if (!filters_arr)
560 return -ENOMEM;
561 filters->filters_arr = filters_arr;
562
563 for (i = 0; i < nr_filters; i++) {
564 filter = damon_sysfs_scheme_filter_alloc();
565 if (!filter) {
566 damon_sysfs_scheme_filters_rm_dirs(filters);
567 return -ENOMEM;
568 }
569
570 err = kobject_init_and_add(&filter->kobj,
571 &damon_sysfs_scheme_filter_ktype,
572 &filters->kobj, "%d", i);
573 if (err) {
574 kobject_put(&filter->kobj);
575 damon_sysfs_scheme_filters_rm_dirs(filters);
576 return err;
577 }
578
579 filters_arr[i] = filter;
580 filters->nr++;
581 }
582 return 0;
583}
584
ac35264b
SP
585static ssize_t nr_filters_show(struct kobject *kobj,
586 struct kobj_attribute *attr, char *buf)
587{
588 struct damon_sysfs_scheme_filters *filters = container_of(kobj,
589 struct damon_sysfs_scheme_filters, kobj);
590
591 return sysfs_emit(buf, "%d\n", filters->nr);
592}
593
594static ssize_t nr_filters_store(struct kobject *kobj,
595 struct kobj_attribute *attr, const char *buf, size_t count)
596{
472e2b70 597 struct damon_sysfs_scheme_filters *filters;
ac35264b
SP
598 int nr, err = kstrtoint(buf, 0, &nr);
599
600 if (err)
601 return err;
602 if (nr < 0)
603 return -EINVAL;
604
472e2b70
SP
605 filters = container_of(kobj, struct damon_sysfs_scheme_filters, kobj);
606
607 if (!mutex_trylock(&damon_sysfs_lock))
608 return -EBUSY;
609 err = damon_sysfs_scheme_filters_add_dirs(filters, nr);
610 mutex_unlock(&damon_sysfs_lock);
611 if (err)
612 return err;
613
ac35264b
SP
614 return count;
615}
616
617static void damon_sysfs_scheme_filters_release(struct kobject *kobj)
618{
619 kfree(container_of(kobj, struct damon_sysfs_scheme_filters, kobj));
620}
621
622static struct kobj_attribute damon_sysfs_scheme_filters_nr_attr =
623 __ATTR_RW_MODE(nr_filters, 0600);
624
625static struct attribute *damon_sysfs_scheme_filters_attrs[] = {
626 &damon_sysfs_scheme_filters_nr_attr.attr,
627 NULL,
628};
629ATTRIBUTE_GROUPS(damon_sysfs_scheme_filters);
630
02cd4eb8 631static const struct kobj_type damon_sysfs_scheme_filters_ktype = {
ac35264b
SP
632 .release = damon_sysfs_scheme_filters_release,
633 .sysfs_ops = &kobj_sysfs_ops,
634 .default_groups = damon_sysfs_scheme_filters_groups,
635};
636
c8e7b4d0
SP
637/*
638 * watermarks directory
639 */
640
641struct damon_sysfs_watermarks {
642 struct kobject kobj;
643 enum damos_wmark_metric metric;
644 unsigned long interval_us;
645 unsigned long high;
646 unsigned long mid;
647 unsigned long low;
648};
649
650static struct damon_sysfs_watermarks *damon_sysfs_watermarks_alloc(
651 enum damos_wmark_metric metric, unsigned long interval_us,
652 unsigned long high, unsigned long mid, unsigned long low)
653{
654 struct damon_sysfs_watermarks *watermarks = kmalloc(
655 sizeof(*watermarks), GFP_KERNEL);
656
657 if (!watermarks)
658 return NULL;
659 watermarks->kobj = (struct kobject){};
660 watermarks->metric = metric;
661 watermarks->interval_us = interval_us;
662 watermarks->high = high;
663 watermarks->mid = mid;
664 watermarks->low = low;
665 return watermarks;
666}
667
668/* Should match with enum damos_wmark_metric */
669static const char * const damon_sysfs_wmark_metric_strs[] = {
670 "none",
671 "free_mem_rate",
672};
673
674static ssize_t metric_show(struct kobject *kobj, struct kobj_attribute *attr,
675 char *buf)
676{
677 struct damon_sysfs_watermarks *watermarks = container_of(kobj,
678 struct damon_sysfs_watermarks, kobj);
679
680 return sysfs_emit(buf, "%s\n",
681 damon_sysfs_wmark_metric_strs[watermarks->metric]);
682}
683
684static ssize_t metric_store(struct kobject *kobj, struct kobj_attribute *attr,
685 const char *buf, size_t count)
686{
687 struct damon_sysfs_watermarks *watermarks = container_of(kobj,
688 struct damon_sysfs_watermarks, kobj);
689 enum damos_wmark_metric metric;
690
691 for (metric = 0; metric < NR_DAMOS_WMARK_METRICS; metric++) {
692 if (sysfs_streq(buf, damon_sysfs_wmark_metric_strs[metric])) {
693 watermarks->metric = metric;
694 return count;
695 }
696 }
697 return -EINVAL;
698}
699
700static ssize_t interval_us_show(struct kobject *kobj,
701 struct kobj_attribute *attr, char *buf)
702{
703 struct damon_sysfs_watermarks *watermarks = container_of(kobj,
704 struct damon_sysfs_watermarks, kobj);
705
706 return sysfs_emit(buf, "%lu\n", watermarks->interval_us);
707}
708
709static ssize_t interval_us_store(struct kobject *kobj,
710 struct kobj_attribute *attr, const char *buf, size_t count)
711{
712 struct damon_sysfs_watermarks *watermarks = container_of(kobj,
713 struct damon_sysfs_watermarks, kobj);
714 int err = kstrtoul(buf, 0, &watermarks->interval_us);
715
716 return err ? err : count;
717}
718
719static ssize_t high_show(struct kobject *kobj,
720 struct kobj_attribute *attr, char *buf)
721{
722 struct damon_sysfs_watermarks *watermarks = container_of(kobj,
723 struct damon_sysfs_watermarks, kobj);
724
725 return sysfs_emit(buf, "%lu\n", watermarks->high);
726}
727
728static ssize_t high_store(struct kobject *kobj,
729 struct kobj_attribute *attr, const char *buf, size_t count)
730{
731 struct damon_sysfs_watermarks *watermarks = container_of(kobj,
732 struct damon_sysfs_watermarks, kobj);
733 int err = kstrtoul(buf, 0, &watermarks->high);
734
735 return err ? err : count;
736}
737
738static ssize_t mid_show(struct kobject *kobj,
739 struct kobj_attribute *attr, char *buf)
740{
741 struct damon_sysfs_watermarks *watermarks = container_of(kobj,
742 struct damon_sysfs_watermarks, kobj);
743
744 return sysfs_emit(buf, "%lu\n", watermarks->mid);
745}
746
747static ssize_t mid_store(struct kobject *kobj,
748 struct kobj_attribute *attr, const char *buf, size_t count)
749{
750 struct damon_sysfs_watermarks *watermarks = container_of(kobj,
751 struct damon_sysfs_watermarks, kobj);
752 int err = kstrtoul(buf, 0, &watermarks->mid);
753
754 return err ? err : count;
755}
756
757static ssize_t low_show(struct kobject *kobj,
758 struct kobj_attribute *attr, char *buf)
759{
760 struct damon_sysfs_watermarks *watermarks = container_of(kobj,
761 struct damon_sysfs_watermarks, kobj);
762
763 return sysfs_emit(buf, "%lu\n", watermarks->low);
764}
765
766static ssize_t low_store(struct kobject *kobj,
767 struct kobj_attribute *attr, const char *buf, size_t count)
768{
769 struct damon_sysfs_watermarks *watermarks = container_of(kobj,
770 struct damon_sysfs_watermarks, kobj);
771 int err = kstrtoul(buf, 0, &watermarks->low);
772
773 return err ? err : count;
774}
775
776static void damon_sysfs_watermarks_release(struct kobject *kobj)
777{
778 kfree(container_of(kobj, struct damon_sysfs_watermarks, kobj));
779}
780
781static struct kobj_attribute damon_sysfs_watermarks_metric_attr =
782 __ATTR_RW_MODE(metric, 0600);
783
784static struct kobj_attribute damon_sysfs_watermarks_interval_us_attr =
785 __ATTR_RW_MODE(interval_us, 0600);
786
787static struct kobj_attribute damon_sysfs_watermarks_high_attr =
788 __ATTR_RW_MODE(high, 0600);
789
790static struct kobj_attribute damon_sysfs_watermarks_mid_attr =
791 __ATTR_RW_MODE(mid, 0600);
792
793static struct kobj_attribute damon_sysfs_watermarks_low_attr =
794 __ATTR_RW_MODE(low, 0600);
795
796static struct attribute *damon_sysfs_watermarks_attrs[] = {
797 &damon_sysfs_watermarks_metric_attr.attr,
798 &damon_sysfs_watermarks_interval_us_attr.attr,
799 &damon_sysfs_watermarks_high_attr.attr,
800 &damon_sysfs_watermarks_mid_attr.attr,
801 &damon_sysfs_watermarks_low_attr.attr,
802 NULL,
803};
804ATTRIBUTE_GROUPS(damon_sysfs_watermarks);
805
e56397e8 806static const struct kobj_type damon_sysfs_watermarks_ktype = {
c8e7b4d0
SP
807 .release = damon_sysfs_watermarks_release,
808 .sysfs_ops = &kobj_sysfs_ops,
809 .default_groups = damon_sysfs_watermarks_groups,
810};
811
812/*
813 * scheme/weights directory
814 */
815
816struct damon_sysfs_weights {
817 struct kobject kobj;
818 unsigned int sz;
819 unsigned int nr_accesses;
820 unsigned int age;
821};
822
823static struct damon_sysfs_weights *damon_sysfs_weights_alloc(unsigned int sz,
824 unsigned int nr_accesses, unsigned int age)
825{
826 struct damon_sysfs_weights *weights = kmalloc(sizeof(*weights),
827 GFP_KERNEL);
828
829 if (!weights)
830 return NULL;
831 weights->kobj = (struct kobject){};
832 weights->sz = sz;
833 weights->nr_accesses = nr_accesses;
834 weights->age = age;
835 return weights;
836}
837
838static ssize_t sz_permil_show(struct kobject *kobj,
839 struct kobj_attribute *attr, char *buf)
840{
841 struct damon_sysfs_weights *weights = container_of(kobj,
842 struct damon_sysfs_weights, kobj);
843
844 return sysfs_emit(buf, "%u\n", weights->sz);
845}
846
847static ssize_t sz_permil_store(struct kobject *kobj,
848 struct kobj_attribute *attr, const char *buf, size_t count)
849{
850 struct damon_sysfs_weights *weights = container_of(kobj,
851 struct damon_sysfs_weights, kobj);
852 int err = kstrtouint(buf, 0, &weights->sz);
853
854 return err ? err : count;
855}
856
857static ssize_t nr_accesses_permil_show(struct kobject *kobj,
858 struct kobj_attribute *attr, char *buf)
859{
860 struct damon_sysfs_weights *weights = container_of(kobj,
861 struct damon_sysfs_weights, kobj);
862
863 return sysfs_emit(buf, "%u\n", weights->nr_accesses);
864}
865
866static ssize_t nr_accesses_permil_store(struct kobject *kobj,
867 struct kobj_attribute *attr, const char *buf, size_t count)
868{
869 struct damon_sysfs_weights *weights = container_of(kobj,
870 struct damon_sysfs_weights, kobj);
871 int err = kstrtouint(buf, 0, &weights->nr_accesses);
872
873 return err ? err : count;
874}
875
876static ssize_t age_permil_show(struct kobject *kobj,
877 struct kobj_attribute *attr, char *buf)
878{
879 struct damon_sysfs_weights *weights = container_of(kobj,
880 struct damon_sysfs_weights, kobj);
881
882 return sysfs_emit(buf, "%u\n", weights->age);
883}
884
885static ssize_t age_permil_store(struct kobject *kobj,
886 struct kobj_attribute *attr, const char *buf, size_t count)
887{
888 struct damon_sysfs_weights *weights = container_of(kobj,
889 struct damon_sysfs_weights, kobj);
890 int err = kstrtouint(buf, 0, &weights->age);
891
892 return err ? err : count;
893}
894
895static void damon_sysfs_weights_release(struct kobject *kobj)
896{
897 kfree(container_of(kobj, struct damon_sysfs_weights, kobj));
898}
899
900static struct kobj_attribute damon_sysfs_weights_sz_attr =
901 __ATTR_RW_MODE(sz_permil, 0600);
902
903static struct kobj_attribute damon_sysfs_weights_nr_accesses_attr =
904 __ATTR_RW_MODE(nr_accesses_permil, 0600);
905
906static struct kobj_attribute damon_sysfs_weights_age_attr =
907 __ATTR_RW_MODE(age_permil, 0600);
908
909static struct attribute *damon_sysfs_weights_attrs[] = {
910 &damon_sysfs_weights_sz_attr.attr,
911 &damon_sysfs_weights_nr_accesses_attr.attr,
912 &damon_sysfs_weights_age_attr.attr,
913 NULL,
914};
915ATTRIBUTE_GROUPS(damon_sysfs_weights);
916
e56397e8 917static const struct kobj_type damon_sysfs_weights_ktype = {
c8e7b4d0
SP
918 .release = damon_sysfs_weights_release,
919 .sysfs_ops = &kobj_sysfs_ops,
920 .default_groups = damon_sysfs_weights_groups,
921};
922
923/*
924 * quotas directory
925 */
926
927struct damon_sysfs_quotas {
928 struct kobject kobj;
929 struct damon_sysfs_weights *weights;
930 unsigned long ms;
931 unsigned long sz;
932 unsigned long reset_interval_ms;
933};
934
935static struct damon_sysfs_quotas *damon_sysfs_quotas_alloc(void)
936{
937 return kzalloc(sizeof(struct damon_sysfs_quotas), GFP_KERNEL);
938}
939
940static int damon_sysfs_quotas_add_dirs(struct damon_sysfs_quotas *quotas)
941{
942 struct damon_sysfs_weights *weights;
943 int err;
944
945 weights = damon_sysfs_weights_alloc(0, 0, 0);
946 if (!weights)
947 return -ENOMEM;
948
949 err = kobject_init_and_add(&weights->kobj, &damon_sysfs_weights_ktype,
950 &quotas->kobj, "weights");
951 if (err)
952 kobject_put(&weights->kobj);
953 else
954 quotas->weights = weights;
955 return err;
956}
957
958static void damon_sysfs_quotas_rm_dirs(struct damon_sysfs_quotas *quotas)
959{
960 kobject_put(&quotas->weights->kobj);
961}
962
963static ssize_t ms_show(struct kobject *kobj, struct kobj_attribute *attr,
964 char *buf)
965{
966 struct damon_sysfs_quotas *quotas = container_of(kobj,
967 struct damon_sysfs_quotas, kobj);
968
969 return sysfs_emit(buf, "%lu\n", quotas->ms);
970}
971
972static ssize_t ms_store(struct kobject *kobj, struct kobj_attribute *attr,
973 const char *buf, size_t count)
974{
975 struct damon_sysfs_quotas *quotas = container_of(kobj,
976 struct damon_sysfs_quotas, kobj);
977 int err = kstrtoul(buf, 0, &quotas->ms);
978
979 if (err)
980 return -EINVAL;
981 return count;
982}
983
984static ssize_t bytes_show(struct kobject *kobj, struct kobj_attribute *attr,
985 char *buf)
986{
987 struct damon_sysfs_quotas *quotas = container_of(kobj,
988 struct damon_sysfs_quotas, kobj);
989
990 return sysfs_emit(buf, "%lu\n", quotas->sz);
991}
992
993static ssize_t bytes_store(struct kobject *kobj,
994 struct kobj_attribute *attr, const char *buf, size_t count)
995{
996 struct damon_sysfs_quotas *quotas = container_of(kobj,
997 struct damon_sysfs_quotas, kobj);
998 int err = kstrtoul(buf, 0, &quotas->sz);
999
1000 if (err)
1001 return -EINVAL;
1002 return count;
1003}
1004
1005static ssize_t reset_interval_ms_show(struct kobject *kobj,
1006 struct kobj_attribute *attr, char *buf)
1007{
1008 struct damon_sysfs_quotas *quotas = container_of(kobj,
1009 struct damon_sysfs_quotas, kobj);
1010
1011 return sysfs_emit(buf, "%lu\n", quotas->reset_interval_ms);
1012}
1013
1014static ssize_t reset_interval_ms_store(struct kobject *kobj,
1015 struct kobj_attribute *attr, const char *buf, size_t count)
1016{
1017 struct damon_sysfs_quotas *quotas = container_of(kobj,
1018 struct damon_sysfs_quotas, kobj);
1019 int err = kstrtoul(buf, 0, &quotas->reset_interval_ms);
1020
1021 if (err)
1022 return -EINVAL;
1023 return count;
1024}
1025
1026static void damon_sysfs_quotas_release(struct kobject *kobj)
1027{
1028 kfree(container_of(kobj, struct damon_sysfs_quotas, kobj));
1029}
1030
1031static struct kobj_attribute damon_sysfs_quotas_ms_attr =
1032 __ATTR_RW_MODE(ms, 0600);
1033
1034static struct kobj_attribute damon_sysfs_quotas_sz_attr =
1035 __ATTR_RW_MODE(bytes, 0600);
1036
1037static struct kobj_attribute damon_sysfs_quotas_reset_interval_ms_attr =
1038 __ATTR_RW_MODE(reset_interval_ms, 0600);
1039
1040static struct attribute *damon_sysfs_quotas_attrs[] = {
1041 &damon_sysfs_quotas_ms_attr.attr,
1042 &damon_sysfs_quotas_sz_attr.attr,
1043 &damon_sysfs_quotas_reset_interval_ms_attr.attr,
1044 NULL,
1045};
1046ATTRIBUTE_GROUPS(damon_sysfs_quotas);
1047
e56397e8 1048static const struct kobj_type damon_sysfs_quotas_ktype = {
c8e7b4d0
SP
1049 .release = damon_sysfs_quotas_release,
1050 .sysfs_ops = &kobj_sysfs_ops,
1051 .default_groups = damon_sysfs_quotas_groups,
1052};
1053
1054/*
1055 * access_pattern directory
1056 */
1057
1058struct damon_sysfs_access_pattern {
1059 struct kobject kobj;
1060 struct damon_sysfs_ul_range *sz;
1061 struct damon_sysfs_ul_range *nr_accesses;
1062 struct damon_sysfs_ul_range *age;
1063};
1064
1065static
1066struct damon_sysfs_access_pattern *damon_sysfs_access_pattern_alloc(void)
1067{
1068 struct damon_sysfs_access_pattern *access_pattern =
1069 kmalloc(sizeof(*access_pattern), GFP_KERNEL);
1070
1071 if (!access_pattern)
1072 return NULL;
1073 access_pattern->kobj = (struct kobject){};
1074 return access_pattern;
1075}
1076
1077static int damon_sysfs_access_pattern_add_range_dir(
1078 struct damon_sysfs_access_pattern *access_pattern,
1079 struct damon_sysfs_ul_range **range_dir_ptr,
1080 char *name)
1081{
1082 struct damon_sysfs_ul_range *range = damon_sysfs_ul_range_alloc(0, 0);
1083 int err;
1084
1085 if (!range)
1086 return -ENOMEM;
1087 err = kobject_init_and_add(&range->kobj, &damon_sysfs_ul_range_ktype,
1088 &access_pattern->kobj, name);
1089 if (err)
1090 kobject_put(&range->kobj);
1091 else
1092 *range_dir_ptr = range;
1093 return err;
1094}
1095
1096static int damon_sysfs_access_pattern_add_dirs(
1097 struct damon_sysfs_access_pattern *access_pattern)
1098{
1099 int err;
1100
1101 err = damon_sysfs_access_pattern_add_range_dir(access_pattern,
1102 &access_pattern->sz, "sz");
1103 if (err)
1104 goto put_sz_out;
1105
1106 err = damon_sysfs_access_pattern_add_range_dir(access_pattern,
1107 &access_pattern->nr_accesses, "nr_accesses");
1108 if (err)
1109 goto put_nr_accesses_sz_out;
1110
1111 err = damon_sysfs_access_pattern_add_range_dir(access_pattern,
1112 &access_pattern->age, "age");
1113 if (err)
1114 goto put_age_nr_accesses_sz_out;
1115 return 0;
1116
1117put_age_nr_accesses_sz_out:
1118 kobject_put(&access_pattern->age->kobj);
1119 access_pattern->age = NULL;
1120put_nr_accesses_sz_out:
1121 kobject_put(&access_pattern->nr_accesses->kobj);
1122 access_pattern->nr_accesses = NULL;
1123put_sz_out:
1124 kobject_put(&access_pattern->sz->kobj);
1125 access_pattern->sz = NULL;
1126 return err;
1127}
1128
1129static void damon_sysfs_access_pattern_rm_dirs(
1130 struct damon_sysfs_access_pattern *access_pattern)
1131{
1132 kobject_put(&access_pattern->sz->kobj);
1133 kobject_put(&access_pattern->nr_accesses->kobj);
1134 kobject_put(&access_pattern->age->kobj);
1135}
1136
1137static void damon_sysfs_access_pattern_release(struct kobject *kobj)
1138{
1139 kfree(container_of(kobj, struct damon_sysfs_access_pattern, kobj));
1140}
1141
1142static struct attribute *damon_sysfs_access_pattern_attrs[] = {
1143 NULL,
1144};
1145ATTRIBUTE_GROUPS(damon_sysfs_access_pattern);
1146
e56397e8 1147static const struct kobj_type damon_sysfs_access_pattern_ktype = {
c8e7b4d0
SP
1148 .release = damon_sysfs_access_pattern_release,
1149 .sysfs_ops = &kobj_sysfs_ops,
1150 .default_groups = damon_sysfs_access_pattern_groups,
1151};
1152
1153/*
1154 * scheme directory
1155 */
1156
1157struct damon_sysfs_scheme {
1158 struct kobject kobj;
1159 enum damos_action action;
1160 struct damon_sysfs_access_pattern *access_pattern;
a2a9f68e 1161 unsigned long apply_interval_us;
c8e7b4d0
SP
1162 struct damon_sysfs_quotas *quotas;
1163 struct damon_sysfs_watermarks *watermarks;
ac35264b 1164 struct damon_sysfs_scheme_filters *filters;
c8e7b4d0 1165 struct damon_sysfs_stats *stats;
5181b75f 1166 struct damon_sysfs_scheme_regions *tried_regions;
c8e7b4d0
SP
1167};
1168
1169/* This should match with enum damos_action */
1170static const char * const damon_sysfs_damos_action_strs[] = {
1171 "willneed",
1172 "cold",
1173 "pageout",
1174 "hugepage",
1175 "nohugepage",
1176 "lru_prio",
1177 "lru_deprio",
1178 "stat",
1179};
1180
1181static struct damon_sysfs_scheme *damon_sysfs_scheme_alloc(
a2a9f68e 1182 enum damos_action action, unsigned long apply_interval_us)
c8e7b4d0
SP
1183{
1184 struct damon_sysfs_scheme *scheme = kmalloc(sizeof(*scheme),
1185 GFP_KERNEL);
1186
1187 if (!scheme)
1188 return NULL;
1189 scheme->kobj = (struct kobject){};
1190 scheme->action = action;
a2a9f68e 1191 scheme->apply_interval_us = apply_interval_us;
c8e7b4d0
SP
1192 return scheme;
1193}
1194
1195static int damon_sysfs_scheme_set_access_pattern(
1196 struct damon_sysfs_scheme *scheme)
1197{
1198 struct damon_sysfs_access_pattern *access_pattern;
1199 int err;
1200
1201 access_pattern = damon_sysfs_access_pattern_alloc();
1202 if (!access_pattern)
1203 return -ENOMEM;
1204 err = kobject_init_and_add(&access_pattern->kobj,
1205 &damon_sysfs_access_pattern_ktype, &scheme->kobj,
1206 "access_pattern");
1207 if (err)
1208 goto out;
1209 err = damon_sysfs_access_pattern_add_dirs(access_pattern);
1210 if (err)
1211 goto out;
1212 scheme->access_pattern = access_pattern;
1213 return 0;
1214
1215out:
1216 kobject_put(&access_pattern->kobj);
1217 return err;
1218}
1219
1220static int damon_sysfs_scheme_set_quotas(struct damon_sysfs_scheme *scheme)
1221{
1222 struct damon_sysfs_quotas *quotas = damon_sysfs_quotas_alloc();
1223 int err;
1224
1225 if (!quotas)
1226 return -ENOMEM;
1227 err = kobject_init_and_add(&quotas->kobj, &damon_sysfs_quotas_ktype,
1228 &scheme->kobj, "quotas");
1229 if (err)
1230 goto out;
1231 err = damon_sysfs_quotas_add_dirs(quotas);
1232 if (err)
1233 goto out;
1234 scheme->quotas = quotas;
1235 return 0;
1236
1237out:
1238 kobject_put(&quotas->kobj);
1239 return err;
1240}
1241
1242static int damon_sysfs_scheme_set_watermarks(struct damon_sysfs_scheme *scheme)
1243{
1244 struct damon_sysfs_watermarks *watermarks =
1245 damon_sysfs_watermarks_alloc(DAMOS_WMARK_NONE, 0, 0, 0, 0);
1246 int err;
1247
1248 if (!watermarks)
1249 return -ENOMEM;
1250 err = kobject_init_and_add(&watermarks->kobj,
1251 &damon_sysfs_watermarks_ktype, &scheme->kobj,
1252 "watermarks");
1253 if (err)
1254 kobject_put(&watermarks->kobj);
1255 else
1256 scheme->watermarks = watermarks;
1257 return err;
1258}
1259
ac35264b
SP
1260static int damon_sysfs_scheme_set_filters(struct damon_sysfs_scheme *scheme)
1261{
1262 struct damon_sysfs_scheme_filters *filters =
1263 damon_sysfs_scheme_filters_alloc();
1264 int err;
1265
1266 if (!filters)
1267 return -ENOMEM;
1268 err = kobject_init_and_add(&filters->kobj,
1269 &damon_sysfs_scheme_filters_ktype, &scheme->kobj,
1270 "filters");
1271 if (err)
1272 kobject_put(&filters->kobj);
1273 else
1274 scheme->filters = filters;
1275 return err;
1276}
1277
c8e7b4d0
SP
1278static int damon_sysfs_scheme_set_stats(struct damon_sysfs_scheme *scheme)
1279{
1280 struct damon_sysfs_stats *stats = damon_sysfs_stats_alloc();
1281 int err;
1282
1283 if (!stats)
1284 return -ENOMEM;
1285 err = kobject_init_and_add(&stats->kobj, &damon_sysfs_stats_ktype,
1286 &scheme->kobj, "stats");
1287 if (err)
1288 kobject_put(&stats->kobj);
1289 else
1290 scheme->stats = stats;
1291 return err;
1292}
1293
5181b75f
SP
1294static int damon_sysfs_scheme_set_tried_regions(
1295 struct damon_sysfs_scheme *scheme)
1296{
1297 struct damon_sysfs_scheme_regions *tried_regions =
1298 damon_sysfs_scheme_regions_alloc();
1299 int err;
1300
1301 if (!tried_regions)
1302 return -ENOMEM;
1303 err = kobject_init_and_add(&tried_regions->kobj,
1304 &damon_sysfs_scheme_regions_ktype, &scheme->kobj,
1305 "tried_regions");
1306 if (err)
1307 kobject_put(&tried_regions->kobj);
1308 else
1309 scheme->tried_regions = tried_regions;
1310 return err;
1311}
1312
c8e7b4d0
SP
1313static int damon_sysfs_scheme_add_dirs(struct damon_sysfs_scheme *scheme)
1314{
1315 int err;
1316
1317 err = damon_sysfs_scheme_set_access_pattern(scheme);
1318 if (err)
1319 return err;
1320 err = damon_sysfs_scheme_set_quotas(scheme);
1321 if (err)
1322 goto put_access_pattern_out;
1323 err = damon_sysfs_scheme_set_watermarks(scheme);
1324 if (err)
1325 goto put_quotas_access_pattern_out;
ac35264b 1326 err = damon_sysfs_scheme_set_filters(scheme);
c8e7b4d0
SP
1327 if (err)
1328 goto put_watermarks_quotas_access_pattern_out;
ac35264b
SP
1329 err = damon_sysfs_scheme_set_stats(scheme);
1330 if (err)
1331 goto put_filters_watermarks_quotas_access_pattern_out;
5181b75f
SP
1332 err = damon_sysfs_scheme_set_tried_regions(scheme);
1333 if (err)
1334 goto put_tried_regions_out;
c8e7b4d0
SP
1335 return 0;
1336
5181b75f
SP
1337put_tried_regions_out:
1338 kobject_put(&scheme->tried_regions->kobj);
1339 scheme->tried_regions = NULL;
ac35264b
SP
1340put_filters_watermarks_quotas_access_pattern_out:
1341 kobject_put(&scheme->filters->kobj);
1342 scheme->filters = NULL;
c8e7b4d0
SP
1343put_watermarks_quotas_access_pattern_out:
1344 kobject_put(&scheme->watermarks->kobj);
1345 scheme->watermarks = NULL;
1346put_quotas_access_pattern_out:
1347 kobject_put(&scheme->quotas->kobj);
1348 scheme->quotas = NULL;
1349put_access_pattern_out:
1350 kobject_put(&scheme->access_pattern->kobj);
1351 scheme->access_pattern = NULL;
1352 return err;
1353}
1354
1355static void damon_sysfs_scheme_rm_dirs(struct damon_sysfs_scheme *scheme)
1356{
1357 damon_sysfs_access_pattern_rm_dirs(scheme->access_pattern);
1358 kobject_put(&scheme->access_pattern->kobj);
1359 damon_sysfs_quotas_rm_dirs(scheme->quotas);
1360 kobject_put(&scheme->quotas->kobj);
1361 kobject_put(&scheme->watermarks->kobj);
472e2b70 1362 damon_sysfs_scheme_filters_rm_dirs(scheme->filters);
ac35264b 1363 kobject_put(&scheme->filters->kobj);
c8e7b4d0 1364 kobject_put(&scheme->stats->kobj);
9277d036 1365 damon_sysfs_scheme_regions_rm_dirs(scheme->tried_regions);
5181b75f 1366 kobject_put(&scheme->tried_regions->kobj);
c8e7b4d0
SP
1367}
1368
1369static ssize_t action_show(struct kobject *kobj, struct kobj_attribute *attr,
1370 char *buf)
1371{
1372 struct damon_sysfs_scheme *scheme = container_of(kobj,
1373 struct damon_sysfs_scheme, kobj);
1374
1375 return sysfs_emit(buf, "%s\n",
1376 damon_sysfs_damos_action_strs[scheme->action]);
1377}
1378
1379static ssize_t action_store(struct kobject *kobj, struct kobj_attribute *attr,
1380 const char *buf, size_t count)
1381{
1382 struct damon_sysfs_scheme *scheme = container_of(kobj,
1383 struct damon_sysfs_scheme, kobj);
1384 enum damos_action action;
1385
1386 for (action = 0; action < NR_DAMOS_ACTIONS; action++) {
1387 if (sysfs_streq(buf, damon_sysfs_damos_action_strs[action])) {
1388 scheme->action = action;
1389 return count;
1390 }
1391 }
1392 return -EINVAL;
1393}
1394
a2a9f68e
SP
1395static ssize_t apply_interval_us_show(struct kobject *kobj,
1396 struct kobj_attribute *attr, char *buf)
1397{
1398 struct damon_sysfs_scheme *scheme = container_of(kobj,
1399 struct damon_sysfs_scheme, kobj);
1400
1401 return sysfs_emit(buf, "%lu\n", scheme->apply_interval_us);
1402}
1403
1404static ssize_t apply_interval_us_store(struct kobject *kobj,
1405 struct kobj_attribute *attr, const char *buf, size_t count)
1406{
1407 struct damon_sysfs_scheme *scheme = container_of(kobj,
1408 struct damon_sysfs_scheme, kobj);
1409 int err = kstrtoul(buf, 0, &scheme->apply_interval_us);
1410
1411 return err ? err : count;
1412}
1413
c8e7b4d0
SP
1414static void damon_sysfs_scheme_release(struct kobject *kobj)
1415{
1416 kfree(container_of(kobj, struct damon_sysfs_scheme, kobj));
1417}
1418
1419static struct kobj_attribute damon_sysfs_scheme_action_attr =
1420 __ATTR_RW_MODE(action, 0600);
1421
a2a9f68e
SP
1422static struct kobj_attribute damon_sysfs_scheme_apply_interval_us_attr =
1423 __ATTR_RW_MODE(apply_interval_us, 0600);
1424
c8e7b4d0
SP
1425static struct attribute *damon_sysfs_scheme_attrs[] = {
1426 &damon_sysfs_scheme_action_attr.attr,
a2a9f68e 1427 &damon_sysfs_scheme_apply_interval_us_attr.attr,
c8e7b4d0
SP
1428 NULL,
1429};
1430ATTRIBUTE_GROUPS(damon_sysfs_scheme);
1431
e56397e8 1432static const struct kobj_type damon_sysfs_scheme_ktype = {
c8e7b4d0
SP
1433 .release = damon_sysfs_scheme_release,
1434 .sysfs_ops = &kobj_sysfs_ops,
1435 .default_groups = damon_sysfs_scheme_groups,
1436};
1437
1438/*
1439 * schemes directory
1440 */
1441
1442struct damon_sysfs_schemes *damon_sysfs_schemes_alloc(void)
1443{
1444 return kzalloc(sizeof(struct damon_sysfs_schemes), GFP_KERNEL);
1445}
1446
1447void damon_sysfs_schemes_rm_dirs(struct damon_sysfs_schemes *schemes)
1448{
1449 struct damon_sysfs_scheme **schemes_arr = schemes->schemes_arr;
1450 int i;
1451
1452 for (i = 0; i < schemes->nr; i++) {
1453 damon_sysfs_scheme_rm_dirs(schemes_arr[i]);
1454 kobject_put(&schemes_arr[i]->kobj);
1455 }
1456 schemes->nr = 0;
1457 kfree(schemes_arr);
1458 schemes->schemes_arr = NULL;
1459}
1460
1461static int damon_sysfs_schemes_add_dirs(struct damon_sysfs_schemes *schemes,
1462 int nr_schemes)
1463{
1464 struct damon_sysfs_scheme **schemes_arr, *scheme;
1465 int err, i;
1466
1467 damon_sysfs_schemes_rm_dirs(schemes);
1468 if (!nr_schemes)
1469 return 0;
1470
1471 schemes_arr = kmalloc_array(nr_schemes, sizeof(*schemes_arr),
1472 GFP_KERNEL | __GFP_NOWARN);
1473 if (!schemes_arr)
1474 return -ENOMEM;
1475 schemes->schemes_arr = schemes_arr;
1476
1477 for (i = 0; i < nr_schemes; i++) {
a2a9f68e
SP
1478 /*
1479 * apply_interval_us as 0 means same to aggregation interval
1480 * (same to before-apply_interval behavior)
1481 */
1482 scheme = damon_sysfs_scheme_alloc(DAMOS_STAT, 0);
c8e7b4d0
SP
1483 if (!scheme) {
1484 damon_sysfs_schemes_rm_dirs(schemes);
1485 return -ENOMEM;
1486 }
1487
1488 err = kobject_init_and_add(&scheme->kobj,
1489 &damon_sysfs_scheme_ktype, &schemes->kobj,
1490 "%d", i);
1491 if (err)
1492 goto out;
1493 err = damon_sysfs_scheme_add_dirs(scheme);
1494 if (err)
1495 goto out;
1496
1497 schemes_arr[i] = scheme;
1498 schemes->nr++;
1499 }
1500 return 0;
1501
1502out:
1503 damon_sysfs_schemes_rm_dirs(schemes);
1504 kobject_put(&scheme->kobj);
1505 return err;
1506}
1507
1508static ssize_t nr_schemes_show(struct kobject *kobj,
1509 struct kobj_attribute *attr, char *buf)
1510{
1511 struct damon_sysfs_schemes *schemes = container_of(kobj,
1512 struct damon_sysfs_schemes, kobj);
1513
1514 return sysfs_emit(buf, "%d\n", schemes->nr);
1515}
1516
1517static ssize_t nr_schemes_store(struct kobject *kobj,
1518 struct kobj_attribute *attr, const char *buf, size_t count)
1519{
1520 struct damon_sysfs_schemes *schemes;
1521 int nr, err = kstrtoint(buf, 0, &nr);
1522
1523 if (err)
1524 return err;
1525 if (nr < 0)
1526 return -EINVAL;
1527
1528 schemes = container_of(kobj, struct damon_sysfs_schemes, kobj);
1529
1530 if (!mutex_trylock(&damon_sysfs_lock))
1531 return -EBUSY;
1532 err = damon_sysfs_schemes_add_dirs(schemes, nr);
1533 mutex_unlock(&damon_sysfs_lock);
1534 if (err)
1535 return err;
1536 return count;
1537}
1538
1539static void damon_sysfs_schemes_release(struct kobject *kobj)
1540{
1541 kfree(container_of(kobj, struct damon_sysfs_schemes, kobj));
1542}
1543
1544static struct kobj_attribute damon_sysfs_schemes_nr_attr =
1545 __ATTR_RW_MODE(nr_schemes, 0600);
1546
1547static struct attribute *damon_sysfs_schemes_attrs[] = {
1548 &damon_sysfs_schemes_nr_attr.attr,
1549 NULL,
1550};
1551ATTRIBUTE_GROUPS(damon_sysfs_schemes);
1552
e56397e8 1553const struct kobj_type damon_sysfs_schemes_ktype = {
c8e7b4d0
SP
1554 .release = damon_sysfs_schemes_release,
1555 .sysfs_ops = &kobj_sysfs_ops,
1556 .default_groups = damon_sysfs_schemes_groups,
1557};
1558
29cbb9a1
SP
1559static bool damon_sysfs_memcg_path_eq(struct mem_cgroup *memcg,
1560 char *memcg_path_buf, char *path)
1561{
1562#ifdef CONFIG_MEMCG
1563 cgroup_path(memcg->css.cgroup, memcg_path_buf, PATH_MAX);
1564 if (sysfs_streq(memcg_path_buf, path))
1565 return true;
1566#endif /* CONFIG_MEMCG */
1567 return false;
1568}
1569
1570static int damon_sysfs_memcg_path_to_id(char *memcg_path, unsigned short *id)
1571{
1572 struct mem_cgroup *memcg;
1573 char *path;
1574 bool found = false;
1575
1576 if (!memcg_path)
1577 return -EINVAL;
1578
1579 path = kmalloc(sizeof(*path) * PATH_MAX, GFP_KERNEL);
1580 if (!path)
1581 return -ENOMEM;
1582
1583 for (memcg = mem_cgroup_iter(NULL, NULL, NULL); memcg;
1584 memcg = mem_cgroup_iter(NULL, memcg, NULL)) {
1585 /* skip removed memcg */
1586 if (!mem_cgroup_id(memcg))
1587 continue;
1588 if (damon_sysfs_memcg_path_eq(memcg, path, memcg_path)) {
1589 *id = mem_cgroup_id(memcg);
1590 found = true;
1591 break;
1592 }
1593 }
1594
1595 kfree(path);
1596 return found ? 0 : -EINVAL;
1597}
1598
1599static int damon_sysfs_set_scheme_filters(struct damos *scheme,
1600 struct damon_sysfs_scheme_filters *sysfs_filters)
1601{
1602 int i;
1603 struct damos_filter *filter, *next;
1604
1605 damos_for_each_filter_safe(filter, next, scheme)
1606 damos_destroy_filter(filter);
1607
1608 for (i = 0; i < sysfs_filters->nr; i++) {
1609 struct damon_sysfs_scheme_filter *sysfs_filter =
1610 sysfs_filters->filters_arr[i];
1611 struct damos_filter *filter =
1612 damos_new_filter(sysfs_filter->type,
1613 sysfs_filter->matching);
1614 int err;
1615
1616 if (!filter)
1617 return -ENOMEM;
1618 if (filter->type == DAMOS_FILTER_TYPE_MEMCG) {
1619 err = damon_sysfs_memcg_path_to_id(
1620 sysfs_filter->memcg_path,
1621 &filter->memcg_id);
1622 if (err) {
1623 damos_destroy_filter(filter);
1624 return err;
1625 }
2f1abcfc
SP
1626 } else if (filter->type == DAMOS_FILTER_TYPE_ADDR) {
1627 if (sysfs_filter->addr_range.end <
1628 sysfs_filter->addr_range.start) {
1629 damos_destroy_filter(filter);
1630 return -EINVAL;
1631 }
1632 filter->addr_range = sysfs_filter->addr_range;
9f6e47ab
SP
1633 } else if (filter->type == DAMOS_FILTER_TYPE_TARGET) {
1634 filter->target_idx = sysfs_filter->target_idx;
29cbb9a1 1635 }
2f1abcfc 1636
29cbb9a1
SP
1637 damos_add_filter(scheme, filter);
1638 }
1639 return 0;
1640}
1641
c8e7b4d0
SP
1642static struct damos *damon_sysfs_mk_scheme(
1643 struct damon_sysfs_scheme *sysfs_scheme)
1644{
1645 struct damon_sysfs_access_pattern *access_pattern =
1646 sysfs_scheme->access_pattern;
1647 struct damon_sysfs_quotas *sysfs_quotas = sysfs_scheme->quotas;
1648 struct damon_sysfs_weights *sysfs_weights = sysfs_quotas->weights;
1649 struct damon_sysfs_watermarks *sysfs_wmarks = sysfs_scheme->watermarks;
29cbb9a1
SP
1650 struct damon_sysfs_scheme_filters *sysfs_filters =
1651 sysfs_scheme->filters;
1652 struct damos *scheme;
1653 int err;
c8e7b4d0
SP
1654
1655 struct damos_access_pattern pattern = {
1656 .min_sz_region = access_pattern->sz->min,
1657 .max_sz_region = access_pattern->sz->max,
1658 .min_nr_accesses = access_pattern->nr_accesses->min,
1659 .max_nr_accesses = access_pattern->nr_accesses->max,
1660 .min_age_region = access_pattern->age->min,
1661 .max_age_region = access_pattern->age->max,
1662 };
1663 struct damos_quota quota = {
1664 .ms = sysfs_quotas->ms,
1665 .sz = sysfs_quotas->sz,
1666 .reset_interval = sysfs_quotas->reset_interval_ms,
1667 .weight_sz = sysfs_weights->sz,
1668 .weight_nr_accesses = sysfs_weights->nr_accesses,
1669 .weight_age = sysfs_weights->age,
1670 };
1671 struct damos_watermarks wmarks = {
1672 .metric = sysfs_wmarks->metric,
1673 .interval = sysfs_wmarks->interval_us,
1674 .high = sysfs_wmarks->high,
1675 .mid = sysfs_wmarks->mid,
1676 .low = sysfs_wmarks->low,
1677 };
1678
a2a9f68e
SP
1679 scheme = damon_new_scheme(&pattern, sysfs_scheme->action,
1680 sysfs_scheme->apply_interval_us, &quota, &wmarks);
29cbb9a1
SP
1681 if (!scheme)
1682 return NULL;
1683
1684 err = damon_sysfs_set_scheme_filters(scheme, sysfs_filters);
1685 if (err) {
1686 damon_destroy_scheme(scheme);
1687 return NULL;
1688 }
1689 return scheme;
c8e7b4d0
SP
1690}
1691
1692static void damon_sysfs_update_scheme(struct damos *scheme,
1693 struct damon_sysfs_scheme *sysfs_scheme)
1694{
1695 struct damon_sysfs_access_pattern *access_pattern =
1696 sysfs_scheme->access_pattern;
1697 struct damon_sysfs_quotas *sysfs_quotas = sysfs_scheme->quotas;
1698 struct damon_sysfs_weights *sysfs_weights = sysfs_quotas->weights;
1699 struct damon_sysfs_watermarks *sysfs_wmarks = sysfs_scheme->watermarks;
29cbb9a1 1700 int err;
c8e7b4d0
SP
1701
1702 scheme->pattern.min_sz_region = access_pattern->sz->min;
1703 scheme->pattern.max_sz_region = access_pattern->sz->max;
1704 scheme->pattern.min_nr_accesses = access_pattern->nr_accesses->min;
1705 scheme->pattern.max_nr_accesses = access_pattern->nr_accesses->max;
1706 scheme->pattern.min_age_region = access_pattern->age->min;
1707 scheme->pattern.max_age_region = access_pattern->age->max;
1708
1709 scheme->action = sysfs_scheme->action;
a2a9f68e 1710 scheme->apply_interval_us = sysfs_scheme->apply_interval_us;
c8e7b4d0
SP
1711
1712 scheme->quota.ms = sysfs_quotas->ms;
1713 scheme->quota.sz = sysfs_quotas->sz;
1714 scheme->quota.reset_interval = sysfs_quotas->reset_interval_ms;
1715 scheme->quota.weight_sz = sysfs_weights->sz;
1716 scheme->quota.weight_nr_accesses = sysfs_weights->nr_accesses;
1717 scheme->quota.weight_age = sysfs_weights->age;
1718
1719 scheme->wmarks.metric = sysfs_wmarks->metric;
1720 scheme->wmarks.interval = sysfs_wmarks->interval_us;
1721 scheme->wmarks.high = sysfs_wmarks->high;
1722 scheme->wmarks.mid = sysfs_wmarks->mid;
1723 scheme->wmarks.low = sysfs_wmarks->low;
29cbb9a1
SP
1724
1725 err = damon_sysfs_set_scheme_filters(scheme, sysfs_scheme->filters);
1726 if (err)
1727 damon_destroy_scheme(scheme);
c8e7b4d0
SP
1728}
1729
1730int damon_sysfs_set_schemes(struct damon_ctx *ctx,
1731 struct damon_sysfs_schemes *sysfs_schemes)
1732{
1733 struct damos *scheme, *next;
1734 int i = 0;
1735
1736 damon_for_each_scheme_safe(scheme, next, ctx) {
1737 if (i < sysfs_schemes->nr)
1738 damon_sysfs_update_scheme(scheme,
1739 sysfs_schemes->schemes_arr[i]);
1740 else
1741 damon_destroy_scheme(scheme);
1742 i++;
1743 }
1744
1745 for (; i < sysfs_schemes->nr; i++) {
1746 struct damos *scheme, *next;
1747
1748 scheme = damon_sysfs_mk_scheme(sysfs_schemes->schemes_arr[i]);
1749 if (!scheme) {
1750 damon_for_each_scheme_safe(scheme, next, ctx)
1751 damon_destroy_scheme(scheme);
1752 return -ENOMEM;
1753 }
1754 damon_add_scheme(ctx, scheme);
1755 }
1756 return 0;
1757}
1758
1759void damon_sysfs_schemes_update_stats(
1760 struct damon_sysfs_schemes *sysfs_schemes,
1761 struct damon_ctx *ctx)
1762{
1763 struct damos *scheme;
1764 int schemes_idx = 0;
1765
1766 damon_for_each_scheme(scheme, ctx) {
1767 struct damon_sysfs_stats *sysfs_stats;
1768
1769 /* user could have removed the scheme sysfs dir */
1770 if (schemes_idx >= sysfs_schemes->nr)
1771 break;
1772
1773 sysfs_stats = sysfs_schemes->schemes_arr[schemes_idx++]->stats;
1774 sysfs_stats->nr_tried = scheme->stat.nr_tried;
1775 sysfs_stats->sz_tried = scheme->stat.sz_tried;
1776 sysfs_stats->nr_applied = scheme->stat.nr_applied;
1777 sysfs_stats->sz_applied = scheme->stat.sz_applied;
1778 sysfs_stats->qt_exceeds = scheme->stat.qt_exceeds;
1779 }
1780}
f1d13cac
SP
1781
1782/*
1783 * damon_sysfs_schemes that need to update its schemes regions dir. Protected
1784 * by damon_sysfs_lock
1785 */
1786static struct damon_sysfs_schemes *damon_sysfs_schemes_for_damos_callback;
1787static int damon_sysfs_schemes_region_idx;
6ad243b8 1788static bool damos_regions_upd_total_bytes_only;
f1d13cac
SP
1789
1790/*
1791 * DAMON callback that called before damos apply. While this callback is
1792 * registered, damon_sysfs_lock should be held to ensure the regions
1793 * directories exist.
1794 */
1795static int damon_sysfs_before_damos_apply(struct damon_ctx *ctx,
1796 struct damon_target *t, struct damon_region *r,
1797 struct damos *s)
1798{
1799 struct damos *scheme;
1800 struct damon_sysfs_scheme_regions *sysfs_regions;
1801 struct damon_sysfs_scheme_region *region;
1802 struct damon_sysfs_schemes *sysfs_schemes =
1803 damon_sysfs_schemes_for_damos_callback;
1804 int schemes_idx = 0;
1805
1806 damon_for_each_scheme(scheme, ctx) {
1807 if (scheme == s)
1808 break;
1809 schemes_idx++;
1810 }
1811
1812 /* user could have removed the scheme sysfs dir */
1813 if (schemes_idx >= sysfs_schemes->nr)
1814 return 0;
1815
1816 sysfs_regions = sysfs_schemes->schemes_arr[schemes_idx]->tried_regions;
4d4e41b6
SP
1817 if (sysfs_regions->upd_status == DAMOS_TRIED_REGIONS_UPD_FINISHED)
1818 return 0;
1819 if (sysfs_regions->upd_status == DAMOS_TRIED_REGIONS_UPD_IDLE)
1820 sysfs_regions->upd_status = DAMOS_TRIED_REGIONS_UPD_STARTED;
b69f92a7 1821 sysfs_regions->total_bytes += r->ar.end - r->ar.start;
6ad243b8
SP
1822 if (damos_regions_upd_total_bytes_only)
1823 return 0;
1824
f1d13cac
SP
1825 region = damon_sysfs_scheme_region_alloc(r);
1826 list_add_tail(&region->list, &sysfs_regions->regions_list);
1827 sysfs_regions->nr_regions++;
1828 if (kobject_init_and_add(&region->kobj,
1829 &damon_sysfs_scheme_region_ktype,
1830 &sysfs_regions->kobj, "%d",
1831 damon_sysfs_schemes_region_idx++)) {
1832 kobject_put(&region->kobj);
1833 }
1834 return 0;
1835}
1836
4d4e41b6
SP
1837/*
1838 * DAMON callback that called after each accesses sampling. While this
1839 * callback is registered, damon_sysfs_lock should be held to ensure the
1840 * regions directories exist.
1841 */
1842static int damon_sysfs_after_sampling(struct damon_ctx *ctx)
1843{
1844 struct damon_sysfs_schemes *sysfs_schemes =
1845 damon_sysfs_schemes_for_damos_callback;
1846 struct damon_sysfs_scheme_regions *sysfs_regions;
1847 int i;
1848
1849 for (i = 0; i < sysfs_schemes->nr; i++) {
1850 sysfs_regions = sysfs_schemes->schemes_arr[i]->tried_regions;
1851 if (sysfs_regions->upd_status ==
1852 DAMOS_TRIED_REGIONS_UPD_STARTED)
1853 sysfs_regions->upd_status =
1854 DAMOS_TRIED_REGIONS_UPD_FINISHED;
1855 }
1856
1857 return 0;
1858}
1859
f1d13cac 1860/* Called from damon_sysfs_cmd_request_callback under damon_sysfs_lock */
772c15e5 1861int damon_sysfs_schemes_clear_regions(
f1d13cac
SP
1862 struct damon_sysfs_schemes *sysfs_schemes,
1863 struct damon_ctx *ctx)
1864{
1865 struct damos *scheme;
1866 int schemes_idx = 0;
1867
1868 damon_for_each_scheme(scheme, ctx) {
1869 struct damon_sysfs_scheme *sysfs_scheme;
1870
772c15e5
SP
1871 /* user could have removed the scheme sysfs dir */
1872 if (schemes_idx >= sysfs_schemes->nr)
1873 break;
1874
f1d13cac
SP
1875 sysfs_scheme = sysfs_schemes->schemes_arr[schemes_idx++];
1876 damon_sysfs_scheme_regions_rm_dirs(
1877 sysfs_scheme->tried_regions);
b69f92a7 1878 sysfs_scheme->tried_regions->total_bytes = 0;
f1d13cac 1879 }
772c15e5
SP
1880 return 0;
1881}
f1d13cac 1882
4d4e41b6
SP
1883static void damos_tried_regions_init_upd_status(
1884 struct damon_sysfs_schemes *sysfs_schemes)
1885{
1886 int i;
1887
1888 for (i = 0; i < sysfs_schemes->nr; i++)
1889 sysfs_schemes->schemes_arr[i]->tried_regions->upd_status =
1890 DAMOS_TRIED_REGIONS_UPD_IDLE;
1891}
1892
772c15e5
SP
1893/* Called from damon_sysfs_cmd_request_callback under damon_sysfs_lock */
1894int damon_sysfs_schemes_update_regions_start(
1895 struct damon_sysfs_schemes *sysfs_schemes,
6ad243b8 1896 struct damon_ctx *ctx, bool total_bytes_only)
772c15e5
SP
1897{
1898 damon_sysfs_schemes_clear_regions(sysfs_schemes, ctx);
f1d13cac 1899 damon_sysfs_schemes_for_damos_callback = sysfs_schemes;
4d4e41b6 1900 damos_tried_regions_init_upd_status(sysfs_schemes);
6ad243b8 1901 damos_regions_upd_total_bytes_only = total_bytes_only;
f1d13cac 1902 ctx->callback.before_damos_apply = damon_sysfs_before_damos_apply;
4d4e41b6 1903 ctx->callback.after_sampling = damon_sysfs_after_sampling;
f1d13cac
SP
1904 return 0;
1905}
1906
76126332
SP
1907bool damos_sysfs_regions_upd_done(void)
1908{
1909 struct damon_sysfs_schemes *sysfs_schemes =
1910 damon_sysfs_schemes_for_damos_callback;
1911 struct damon_sysfs_scheme_regions *sysfs_regions;
1912 int i;
1913
1914 for (i = 0; i < sysfs_schemes->nr; i++) {
1915 sysfs_regions = sysfs_schemes->schemes_arr[i]->tried_regions;
1916 if (sysfs_regions->upd_status !=
1917 DAMOS_TRIED_REGIONS_UPD_FINISHED)
1918 return false;
1919 }
1920 return true;
1921}
1922
f1d13cac
SP
1923/*
1924 * Called from damon_sysfs_cmd_request_callback under damon_sysfs_lock. Caller
1925 * should unlock damon_sysfs_lock which held before
1926 * damon_sysfs_schemes_update_regions_start()
1927 */
1928int damon_sysfs_schemes_update_regions_stop(struct damon_ctx *ctx)
1929{
1930 damon_sysfs_schemes_for_damos_callback = NULL;
1931 ctx->callback.before_damos_apply = NULL;
4d4e41b6 1932 ctx->callback.after_sampling = NULL;
f1d13cac
SP
1933 damon_sysfs_schemes_region_idx = 0;
1934 return 0;
1935}