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