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#include <linux/numa.h>
10
11#include "sysfs-common.h"
12
13/*
14 * scheme region directory
15 */
16
17struct damon_sysfs_scheme_region {
18 struct kobject kobj;
19 struct damon_addr_range ar;
20 unsigned int nr_accesses;
21 unsigned int age;
22 unsigned long sz_filter_passed;
23 struct list_head list;
24};
25
26static struct damon_sysfs_scheme_region *damon_sysfs_scheme_region_alloc(
27 struct damon_region *region)
28{
29 struct damon_sysfs_scheme_region *sysfs_region = kmalloc(
30 sizeof(*sysfs_region), GFP_KERNEL);
31
32 if (!sysfs_region)
33 return NULL;
34 sysfs_region->kobj = (struct kobject){};
35 sysfs_region->ar = region->ar;
36 sysfs_region->nr_accesses = region->nr_accesses_bp / 10000;
37 sysfs_region->age = region->age;
38 INIT_LIST_HEAD(list: &sysfs_region->list);
39 return sysfs_region;
40}
41
42static ssize_t start_show(struct kobject *kobj, struct kobj_attribute *attr,
43 char *buf)
44{
45 struct damon_sysfs_scheme_region *region = container_of(kobj,
46 struct damon_sysfs_scheme_region, kobj);
47
48 return sysfs_emit(buf, fmt: "%lu\n", region->ar.start);
49}
50
51static ssize_t end_show(struct kobject *kobj, struct kobj_attribute *attr,
52 char *buf)
53{
54 struct damon_sysfs_scheme_region *region = container_of(kobj,
55 struct damon_sysfs_scheme_region, kobj);
56
57 return sysfs_emit(buf, fmt: "%lu\n", region->ar.end);
58}
59
60static ssize_t nr_accesses_show(struct kobject *kobj,
61 struct kobj_attribute *attr, char *buf)
62{
63 struct damon_sysfs_scheme_region *region = container_of(kobj,
64 struct damon_sysfs_scheme_region, kobj);
65
66 return sysfs_emit(buf, fmt: "%u\n", region->nr_accesses);
67}
68
69static ssize_t age_show(struct kobject *kobj, struct kobj_attribute *attr,
70 char *buf)
71{
72 struct damon_sysfs_scheme_region *region = container_of(kobj,
73 struct damon_sysfs_scheme_region, kobj);
74
75 return sysfs_emit(buf, fmt: "%u\n", region->age);
76}
77
78static ssize_t sz_filter_passed_show(struct kobject *kobj,
79 struct kobj_attribute *attr, char *buf)
80{
81 struct damon_sysfs_scheme_region *region = container_of(kobj,
82 struct damon_sysfs_scheme_region, kobj);
83
84 return sysfs_emit(buf, fmt: "%lu\n", region->sz_filter_passed);
85}
86
87static void damon_sysfs_scheme_region_release(struct kobject *kobj)
88{
89 struct damon_sysfs_scheme_region *region = container_of(kobj,
90 struct damon_sysfs_scheme_region, kobj);
91
92 list_del(entry: &region->list);
93 kfree(objp: region);
94}
95
96static struct kobj_attribute damon_sysfs_scheme_region_start_attr =
97 __ATTR_RO_MODE(start, 0400);
98
99static struct kobj_attribute damon_sysfs_scheme_region_end_attr =
100 __ATTR_RO_MODE(end, 0400);
101
102static struct kobj_attribute damon_sysfs_scheme_region_nr_accesses_attr =
103 __ATTR_RO_MODE(nr_accesses, 0400);
104
105static struct kobj_attribute damon_sysfs_scheme_region_age_attr =
106 __ATTR_RO_MODE(age, 0400);
107
108static struct kobj_attribute damon_sysfs_scheme_region_sz_filter_passed_attr =
109 __ATTR_RO_MODE(sz_filter_passed, 0400);
110
111static struct attribute *damon_sysfs_scheme_region_attrs[] = {
112 &damon_sysfs_scheme_region_start_attr.attr,
113 &damon_sysfs_scheme_region_end_attr.attr,
114 &damon_sysfs_scheme_region_nr_accesses_attr.attr,
115 &damon_sysfs_scheme_region_age_attr.attr,
116 &damon_sysfs_scheme_region_sz_filter_passed_attr.attr,
117 NULL,
118};
119ATTRIBUTE_GROUPS(damon_sysfs_scheme_region);
120
121static const struct kobj_type damon_sysfs_scheme_region_ktype = {
122 .release = damon_sysfs_scheme_region_release,
123 .sysfs_ops = &kobj_sysfs_ops,
124 .default_groups = damon_sysfs_scheme_region_groups,
125};
126
127/*
128 * scheme regions directory
129 */
130
131struct damon_sysfs_scheme_regions {
132 struct kobject kobj;
133 struct list_head regions_list;
134 int nr_regions;
135 unsigned long total_bytes;
136};
137
138static struct damon_sysfs_scheme_regions *
139damon_sysfs_scheme_regions_alloc(void)
140{
141 struct damon_sysfs_scheme_regions *regions = kmalloc(sizeof(*regions),
142 GFP_KERNEL);
143
144 if (!regions)
145 return NULL;
146
147 regions->kobj = (struct kobject){};
148 INIT_LIST_HEAD(list: &regions->regions_list);
149 regions->nr_regions = 0;
150 regions->total_bytes = 0;
151 return regions;
152}
153
154static ssize_t total_bytes_show(struct kobject *kobj,
155 struct kobj_attribute *attr, char *buf)
156{
157 struct damon_sysfs_scheme_regions *regions = container_of(kobj,
158 struct damon_sysfs_scheme_regions, kobj);
159
160 return sysfs_emit(buf, fmt: "%lu\n", regions->total_bytes);
161}
162
163static void damon_sysfs_scheme_regions_rm_dirs(
164 struct damon_sysfs_scheme_regions *regions)
165{
166 struct damon_sysfs_scheme_region *r, *next;
167
168 list_for_each_entry_safe(r, next, &regions->regions_list, list) {
169 /* release function deletes it from the list */
170 kobject_put(kobj: &r->kobj);
171 regions->nr_regions--;
172 }
173}
174
175static void damon_sysfs_scheme_regions_release(struct kobject *kobj)
176{
177 kfree(container_of(kobj, struct damon_sysfs_scheme_regions, kobj));
178}
179
180static struct kobj_attribute damon_sysfs_scheme_regions_total_bytes_attr =
181 __ATTR_RO_MODE(total_bytes, 0400);
182
183static struct attribute *damon_sysfs_scheme_regions_attrs[] = {
184 &damon_sysfs_scheme_regions_total_bytes_attr.attr,
185 NULL,
186};
187ATTRIBUTE_GROUPS(damon_sysfs_scheme_regions);
188
189static const struct kobj_type damon_sysfs_scheme_regions_ktype = {
190 .release = damon_sysfs_scheme_regions_release,
191 .sysfs_ops = &kobj_sysfs_ops,
192 .default_groups = damon_sysfs_scheme_regions_groups,
193};
194
195/*
196 * schemes/stats directory
197 */
198
199struct damon_sysfs_stats {
200 struct kobject kobj;
201 unsigned long nr_tried;
202 unsigned long sz_tried;
203 unsigned long nr_applied;
204 unsigned long sz_applied;
205 unsigned long sz_ops_filter_passed;
206 unsigned long qt_exceeds;
207};
208
209static struct damon_sysfs_stats *damon_sysfs_stats_alloc(void)
210{
211 return kzalloc(sizeof(struct damon_sysfs_stats), GFP_KERNEL);
212}
213
214static ssize_t nr_tried_show(struct kobject *kobj, struct kobj_attribute *attr,
215 char *buf)
216{
217 struct damon_sysfs_stats *stats = container_of(kobj,
218 struct damon_sysfs_stats, kobj);
219
220 return sysfs_emit(buf, fmt: "%lu\n", stats->nr_tried);
221}
222
223static ssize_t sz_tried_show(struct kobject *kobj, struct kobj_attribute *attr,
224 char *buf)
225{
226 struct damon_sysfs_stats *stats = container_of(kobj,
227 struct damon_sysfs_stats, kobj);
228
229 return sysfs_emit(buf, fmt: "%lu\n", stats->sz_tried);
230}
231
232static ssize_t nr_applied_show(struct kobject *kobj,
233 struct kobj_attribute *attr, char *buf)
234{
235 struct damon_sysfs_stats *stats = container_of(kobj,
236 struct damon_sysfs_stats, kobj);
237
238 return sysfs_emit(buf, fmt: "%lu\n", stats->nr_applied);
239}
240
241static ssize_t sz_applied_show(struct kobject *kobj,
242 struct kobj_attribute *attr, char *buf)
243{
244 struct damon_sysfs_stats *stats = container_of(kobj,
245 struct damon_sysfs_stats, kobj);
246
247 return sysfs_emit(buf, fmt: "%lu\n", stats->sz_applied);
248}
249
250static ssize_t sz_ops_filter_passed_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, fmt: "%lu\n", stats->sz_ops_filter_passed);
257}
258
259static ssize_t qt_exceeds_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, fmt: "%lu\n", stats->qt_exceeds);
266}
267
268static void damon_sysfs_stats_release(struct kobject *kobj)
269{
270 kfree(container_of(kobj, struct damon_sysfs_stats, kobj));
271}
272
273static struct kobj_attribute damon_sysfs_stats_nr_tried_attr =
274 __ATTR_RO_MODE(nr_tried, 0400);
275
276static struct kobj_attribute damon_sysfs_stats_sz_tried_attr =
277 __ATTR_RO_MODE(sz_tried, 0400);
278
279static struct kobj_attribute damon_sysfs_stats_nr_applied_attr =
280 __ATTR_RO_MODE(nr_applied, 0400);
281
282static struct kobj_attribute damon_sysfs_stats_sz_applied_attr =
283 __ATTR_RO_MODE(sz_applied, 0400);
284
285static struct kobj_attribute damon_sysfs_stats_sz_ops_filter_passed_attr =
286 __ATTR_RO_MODE(sz_ops_filter_passed, 0400);
287
288static struct kobj_attribute damon_sysfs_stats_qt_exceeds_attr =
289 __ATTR_RO_MODE(qt_exceeds, 0400);
290
291static struct attribute *damon_sysfs_stats_attrs[] = {
292 &damon_sysfs_stats_nr_tried_attr.attr,
293 &damon_sysfs_stats_sz_tried_attr.attr,
294 &damon_sysfs_stats_nr_applied_attr.attr,
295 &damon_sysfs_stats_sz_applied_attr.attr,
296 &damon_sysfs_stats_sz_ops_filter_passed_attr.attr,
297 &damon_sysfs_stats_qt_exceeds_attr.attr,
298 NULL,
299};
300ATTRIBUTE_GROUPS(damon_sysfs_stats);
301
302static const struct kobj_type damon_sysfs_stats_ktype = {
303 .release = damon_sysfs_stats_release,
304 .sysfs_ops = &kobj_sysfs_ops,
305 .default_groups = damon_sysfs_stats_groups,
306};
307
308/*
309 * filter directory
310 */
311
312/*
313 * enum damos_sysfs_filter_handle_layer - Layers handling filters of a dir.
314 */
315enum damos_sysfs_filter_handle_layer {
316 DAMOS_SYSFS_FILTER_HANDLE_LAYER_CORE,
317 DAMOS_SYSFS_FILTER_HANDLE_LAYER_OPS,
318 DAMOS_SYSFS_FILTER_HANDLE_LAYER_BOTH,
319};
320
321struct damon_sysfs_scheme_filter {
322 struct kobject kobj;
323 enum damos_sysfs_filter_handle_layer handle_layer;
324 enum damos_filter_type type;
325 bool matching;
326 bool allow;
327 char *memcg_path;
328 struct damon_addr_range addr_range;
329 struct damon_size_range sz_range;
330 int target_idx;
331};
332
333static struct damon_sysfs_scheme_filter *damon_sysfs_scheme_filter_alloc(
334 enum damos_sysfs_filter_handle_layer layer)
335{
336 struct damon_sysfs_scheme_filter *filter;
337
338 filter = kzalloc(sizeof(struct damon_sysfs_scheme_filter), GFP_KERNEL);
339 if (filter)
340 filter->handle_layer = layer;
341 return filter;
342}
343
344struct damos_sysfs_filter_type_name {
345 enum damos_filter_type type;
346 char *name;
347};
348
349static const struct damos_sysfs_filter_type_name
350damos_sysfs_filter_type_names[] = {
351 {
352 .type = DAMOS_FILTER_TYPE_ANON,
353 .name = "anon",
354 },
355 {
356 .type = DAMOS_FILTER_TYPE_ACTIVE,
357 .name = "active",
358 },
359 {
360 .type = DAMOS_FILTER_TYPE_MEMCG,
361 .name = "memcg",
362 },
363 {
364 .type = DAMOS_FILTER_TYPE_YOUNG,
365 .name = "young",
366 },
367 {
368 .type = DAMOS_FILTER_TYPE_HUGEPAGE_SIZE,
369 .name = "hugepage_size",
370 },
371 {
372 .type = DAMOS_FILTER_TYPE_UNMAPPED,
373 .name = "unmapped",
374 },
375 {
376 .type = DAMOS_FILTER_TYPE_ADDR,
377 .name = "addr",
378 },
379 {
380 .type = DAMOS_FILTER_TYPE_TARGET,
381 .name = "target",
382 },
383};
384
385static ssize_t type_show(struct kobject *kobj,
386 struct kobj_attribute *attr, char *buf)
387{
388 struct damon_sysfs_scheme_filter *filter = container_of(kobj,
389 struct damon_sysfs_scheme_filter, kobj);
390 int i;
391
392 for (i = 0; i < ARRAY_SIZE(damos_sysfs_filter_type_names); i++) {
393 const struct damos_sysfs_filter_type_name *type_name;
394
395 type_name = &damos_sysfs_filter_type_names[i];
396 if (type_name->type == filter->type)
397 return sysfs_emit(buf, fmt: "%s\n", type_name->name);
398 }
399 return -EINVAL;
400}
401
402static bool damos_sysfs_scheme_filter_valid_type(
403 enum damos_sysfs_filter_handle_layer layer,
404 enum damos_filter_type type)
405{
406 switch (layer) {
407 case DAMOS_SYSFS_FILTER_HANDLE_LAYER_BOTH:
408 return true;
409 case DAMOS_SYSFS_FILTER_HANDLE_LAYER_CORE:
410 return !damos_filter_for_ops(type);
411 case DAMOS_SYSFS_FILTER_HANDLE_LAYER_OPS:
412 return damos_filter_for_ops(type);
413 default:
414 break;
415 }
416 return false;
417}
418
419static ssize_t type_store(struct kobject *kobj,
420 struct kobj_attribute *attr, const char *buf, size_t count)
421{
422 struct damon_sysfs_scheme_filter *filter = container_of(kobj,
423 struct damon_sysfs_scheme_filter, kobj);
424 ssize_t ret = -EINVAL;
425 int i;
426
427 for (i = 0; i < ARRAY_SIZE(damos_sysfs_filter_type_names); i++) {
428 const struct damos_sysfs_filter_type_name *type_name;
429
430 type_name = &damos_sysfs_filter_type_names[i];
431 if (sysfs_streq(s1: buf, s2: type_name->name)) {
432 if (!damos_sysfs_scheme_filter_valid_type(
433 layer: filter->handle_layer,
434 type: type_name->type))
435 break;
436 filter->type = type_name->type;
437 ret = count;
438 break;
439 }
440 }
441 return ret;
442}
443
444static ssize_t matching_show(struct kobject *kobj,
445 struct kobj_attribute *attr, char *buf)
446{
447 struct damon_sysfs_scheme_filter *filter = container_of(kobj,
448 struct damon_sysfs_scheme_filter, kobj);
449
450 return sysfs_emit(buf, fmt: "%c\n", filter->matching ? 'Y' : 'N');
451}
452
453static ssize_t matching_store(struct kobject *kobj,
454 struct kobj_attribute *attr, const char *buf, size_t count)
455{
456 struct damon_sysfs_scheme_filter *filter = container_of(kobj,
457 struct damon_sysfs_scheme_filter, kobj);
458 bool matching;
459 int err = kstrtobool(s: buf, res: &matching);
460
461 if (err)
462 return err;
463
464 filter->matching = matching;
465 return count;
466}
467
468static ssize_t allow_show(struct kobject *kobj,
469 struct kobj_attribute *attr, char *buf)
470{
471 struct damon_sysfs_scheme_filter *filter = container_of(kobj,
472 struct damon_sysfs_scheme_filter, kobj);
473
474 return sysfs_emit(buf, fmt: "%c\n", filter->allow ? 'Y' : 'N');
475}
476
477static ssize_t allow_store(struct kobject *kobj,
478 struct kobj_attribute *attr, const char *buf, size_t count)
479{
480 struct damon_sysfs_scheme_filter *filter = container_of(kobj,
481 struct damon_sysfs_scheme_filter, kobj);
482 bool allow;
483 int err = kstrtobool(s: buf, res: &allow);
484
485 if (err)
486 return err;
487
488 filter->allow = allow;
489 return count;
490}
491
492static ssize_t memcg_path_show(struct kobject *kobj,
493 struct kobj_attribute *attr, char *buf)
494{
495 struct damon_sysfs_scheme_filter *filter = container_of(kobj,
496 struct damon_sysfs_scheme_filter, kobj);
497
498 return sysfs_emit(buf, fmt: "%s\n",
499 filter->memcg_path ? filter->memcg_path : "");
500}
501
502static ssize_t memcg_path_store(struct kobject *kobj,
503 struct kobj_attribute *attr, const char *buf, size_t count)
504{
505 struct damon_sysfs_scheme_filter *filter = container_of(kobj,
506 struct damon_sysfs_scheme_filter, kobj);
507 char *path = kmalloc_array(size_add(count, 1), sizeof(*path),
508 GFP_KERNEL);
509
510 if (!path)
511 return -ENOMEM;
512
513 strscpy(path, buf, count + 1);
514 kfree(objp: filter->memcg_path);
515 filter->memcg_path = path;
516 return count;
517}
518
519static ssize_t addr_start_show(struct kobject *kobj,
520 struct kobj_attribute *attr, char *buf)
521{
522 struct damon_sysfs_scheme_filter *filter = container_of(kobj,
523 struct damon_sysfs_scheme_filter, kobj);
524
525 return sysfs_emit(buf, fmt: "%lu\n", filter->addr_range.start);
526}
527
528static ssize_t addr_start_store(struct kobject *kobj,
529 struct kobj_attribute *attr, const char *buf, size_t count)
530{
531 struct damon_sysfs_scheme_filter *filter = container_of(kobj,
532 struct damon_sysfs_scheme_filter, kobj);
533 int err = kstrtoul(s: buf, base: 0, res: &filter->addr_range.start);
534
535 return err ? err : count;
536}
537
538static ssize_t addr_end_show(struct kobject *kobj,
539 struct kobj_attribute *attr, char *buf)
540{
541 struct damon_sysfs_scheme_filter *filter = container_of(kobj,
542 struct damon_sysfs_scheme_filter, kobj);
543
544 return sysfs_emit(buf, fmt: "%lu\n", filter->addr_range.end);
545}
546
547static ssize_t addr_end_store(struct kobject *kobj,
548 struct kobj_attribute *attr, const char *buf, size_t count)
549{
550 struct damon_sysfs_scheme_filter *filter = container_of(kobj,
551 struct damon_sysfs_scheme_filter, kobj);
552 int err = kstrtoul(s: buf, base: 0, res: &filter->addr_range.end);
553
554 return err ? err : count;
555}
556
557static ssize_t min_show(struct kobject *kobj,
558 struct kobj_attribute *attr, char *buf)
559{
560 struct damon_sysfs_scheme_filter *filter = container_of(kobj,
561 struct damon_sysfs_scheme_filter, kobj);
562
563 return sysfs_emit(buf, fmt: "%lu\n", filter->sz_range.min);
564}
565
566static ssize_t min_store(struct kobject *kobj,
567 struct kobj_attribute *attr, const char *buf, size_t count)
568{
569 struct damon_sysfs_scheme_filter *filter = container_of(kobj,
570 struct damon_sysfs_scheme_filter, kobj);
571 int err = kstrtoul(s: buf, base: 0, res: &filter->sz_range.min);
572
573 return err ? err : count;
574}
575
576static ssize_t max_show(struct kobject *kobj,
577 struct kobj_attribute *attr, char *buf)
578{
579 struct damon_sysfs_scheme_filter *filter = container_of(kobj,
580 struct damon_sysfs_scheme_filter, kobj);
581
582 return sysfs_emit(buf, fmt: "%lu\n", filter->sz_range.max);
583}
584
585static ssize_t max_store(struct kobject *kobj,
586 struct kobj_attribute *attr, const char *buf, size_t count)
587{
588 struct damon_sysfs_scheme_filter *filter = container_of(kobj,
589 struct damon_sysfs_scheme_filter, kobj);
590 int err = kstrtoul(s: buf, base: 0, res: &filter->sz_range.max);
591
592 return err ? err : count;
593}
594
595static ssize_t damon_target_idx_show(struct kobject *kobj,
596 struct kobj_attribute *attr, char *buf)
597{
598 struct damon_sysfs_scheme_filter *filter = container_of(kobj,
599 struct damon_sysfs_scheme_filter, kobj);
600
601 return sysfs_emit(buf, fmt: "%d\n", filter->target_idx);
602}
603
604static ssize_t damon_target_idx_store(struct kobject *kobj,
605 struct kobj_attribute *attr, const char *buf, size_t count)
606{
607 struct damon_sysfs_scheme_filter *filter = container_of(kobj,
608 struct damon_sysfs_scheme_filter, kobj);
609 int err = kstrtoint(s: buf, base: 0, res: &filter->target_idx);
610
611 return err ? err : count;
612}
613
614static void damon_sysfs_scheme_filter_release(struct kobject *kobj)
615{
616 struct damon_sysfs_scheme_filter *filter = container_of(kobj,
617 struct damon_sysfs_scheme_filter, kobj);
618
619 kfree(objp: filter->memcg_path);
620 kfree(objp: filter);
621}
622
623static struct kobj_attribute damon_sysfs_scheme_filter_type_attr =
624 __ATTR_RW_MODE(type, 0600);
625
626static struct kobj_attribute damon_sysfs_scheme_filter_matching_attr =
627 __ATTR_RW_MODE(matching, 0600);
628
629static struct kobj_attribute damon_sysfs_scheme_filter_allow_attr =
630 __ATTR_RW_MODE(allow, 0600);
631
632static struct kobj_attribute damon_sysfs_scheme_filter_memcg_path_attr =
633 __ATTR_RW_MODE(memcg_path, 0600);
634
635static struct kobj_attribute damon_sysfs_scheme_filter_addr_start_attr =
636 __ATTR_RW_MODE(addr_start, 0600);
637
638static struct kobj_attribute damon_sysfs_scheme_filter_addr_end_attr =
639 __ATTR_RW_MODE(addr_end, 0600);
640
641static struct kobj_attribute damon_sysfs_scheme_filter_min_attr =
642 __ATTR_RW_MODE(min, 0600);
643
644static struct kobj_attribute damon_sysfs_scheme_filter_max_attr =
645 __ATTR_RW_MODE(max, 0600);
646
647static struct kobj_attribute damon_sysfs_scheme_filter_damon_target_idx_attr =
648 __ATTR_RW_MODE(damon_target_idx, 0600);
649
650static struct attribute *damon_sysfs_scheme_filter_attrs[] = {
651 &damon_sysfs_scheme_filter_type_attr.attr,
652 &damon_sysfs_scheme_filter_matching_attr.attr,
653 &damon_sysfs_scheme_filter_allow_attr.attr,
654 &damon_sysfs_scheme_filter_memcg_path_attr.attr,
655 &damon_sysfs_scheme_filter_addr_start_attr.attr,
656 &damon_sysfs_scheme_filter_addr_end_attr.attr,
657 &damon_sysfs_scheme_filter_min_attr.attr,
658 &damon_sysfs_scheme_filter_max_attr.attr,
659 &damon_sysfs_scheme_filter_damon_target_idx_attr.attr,
660 NULL,
661};
662ATTRIBUTE_GROUPS(damon_sysfs_scheme_filter);
663
664static const struct kobj_type damon_sysfs_scheme_filter_ktype = {
665 .release = damon_sysfs_scheme_filter_release,
666 .sysfs_ops = &kobj_sysfs_ops,
667 .default_groups = damon_sysfs_scheme_filter_groups,
668};
669
670/*
671 * filters directory
672 */
673
674struct damon_sysfs_scheme_filters {
675 struct kobject kobj;
676 enum damos_sysfs_filter_handle_layer handle_layer;
677 struct damon_sysfs_scheme_filter **filters_arr;
678 int nr;
679};
680
681static struct damon_sysfs_scheme_filters *
682damon_sysfs_scheme_filters_alloc(enum damos_sysfs_filter_handle_layer layer)
683{
684 struct damon_sysfs_scheme_filters *filters;
685
686 filters = kzalloc(sizeof(struct damon_sysfs_scheme_filters), GFP_KERNEL);
687 if (filters)
688 filters->handle_layer = layer;
689 return filters;
690}
691
692static void damon_sysfs_scheme_filters_rm_dirs(
693 struct damon_sysfs_scheme_filters *filters)
694{
695 struct damon_sysfs_scheme_filter **filters_arr = filters->filters_arr;
696 int i;
697
698 for (i = 0; i < filters->nr; i++)
699 kobject_put(kobj: &filters_arr[i]->kobj);
700 filters->nr = 0;
701 kfree(objp: filters_arr);
702 filters->filters_arr = NULL;
703}
704
705static int damon_sysfs_scheme_filters_add_dirs(
706 struct damon_sysfs_scheme_filters *filters, int nr_filters)
707{
708 struct damon_sysfs_scheme_filter **filters_arr, *filter;
709 int err, i;
710
711 damon_sysfs_scheme_filters_rm_dirs(filters);
712 if (!nr_filters)
713 return 0;
714
715 filters_arr = kmalloc_array(nr_filters, sizeof(*filters_arr),
716 GFP_KERNEL | __GFP_NOWARN);
717 if (!filters_arr)
718 return -ENOMEM;
719 filters->filters_arr = filters_arr;
720
721 for (i = 0; i < nr_filters; i++) {
722 filter = damon_sysfs_scheme_filter_alloc(
723 layer: filters->handle_layer);
724 if (!filter) {
725 damon_sysfs_scheme_filters_rm_dirs(filters);
726 return -ENOMEM;
727 }
728
729 err = kobject_init_and_add(kobj: &filter->kobj,
730 ktype: &damon_sysfs_scheme_filter_ktype,
731 parent: &filters->kobj, fmt: "%d", i);
732 if (err) {
733 kobject_put(kobj: &filter->kobj);
734 damon_sysfs_scheme_filters_rm_dirs(filters);
735 return err;
736 }
737
738 filters_arr[i] = filter;
739 filters->nr++;
740 }
741 return 0;
742}
743
744static ssize_t nr_filters_show(struct kobject *kobj,
745 struct kobj_attribute *attr, char *buf)
746{
747 struct damon_sysfs_scheme_filters *filters = container_of(kobj,
748 struct damon_sysfs_scheme_filters, kobj);
749
750 return sysfs_emit(buf, fmt: "%d\n", filters->nr);
751}
752
753static ssize_t nr_filters_store(struct kobject *kobj,
754 struct kobj_attribute *attr, const char *buf, size_t count)
755{
756 struct damon_sysfs_scheme_filters *filters;
757 int nr, err = kstrtoint(s: buf, base: 0, res: &nr);
758
759 if (err)
760 return err;
761 if (nr < 0)
762 return -EINVAL;
763
764 filters = container_of(kobj, struct damon_sysfs_scheme_filters, kobj);
765
766 if (!mutex_trylock(&damon_sysfs_lock))
767 return -EBUSY;
768 err = damon_sysfs_scheme_filters_add_dirs(filters, nr_filters: nr);
769 mutex_unlock(lock: &damon_sysfs_lock);
770 if (err)
771 return err;
772
773 return count;
774}
775
776static void damon_sysfs_scheme_filters_release(struct kobject *kobj)
777{
778 kfree(container_of(kobj, struct damon_sysfs_scheme_filters, kobj));
779}
780
781static struct kobj_attribute damon_sysfs_scheme_filters_nr_attr =
782 __ATTR_RW_MODE(nr_filters, 0600);
783
784static struct attribute *damon_sysfs_scheme_filters_attrs[] = {
785 &damon_sysfs_scheme_filters_nr_attr.attr,
786 NULL,
787};
788ATTRIBUTE_GROUPS(damon_sysfs_scheme_filters);
789
790static const struct kobj_type damon_sysfs_scheme_filters_ktype = {
791 .release = damon_sysfs_scheme_filters_release,
792 .sysfs_ops = &kobj_sysfs_ops,
793 .default_groups = damon_sysfs_scheme_filters_groups,
794};
795
796/*
797 * watermarks directory
798 */
799
800struct damon_sysfs_watermarks {
801 struct kobject kobj;
802 enum damos_wmark_metric metric;
803 unsigned long interval_us;
804 unsigned long high;
805 unsigned long mid;
806 unsigned long low;
807};
808
809static struct damon_sysfs_watermarks *damon_sysfs_watermarks_alloc(
810 enum damos_wmark_metric metric, unsigned long interval_us,
811 unsigned long high, unsigned long mid, unsigned long low)
812{
813 struct damon_sysfs_watermarks *watermarks = kmalloc(
814 sizeof(*watermarks), GFP_KERNEL);
815
816 if (!watermarks)
817 return NULL;
818 watermarks->kobj = (struct kobject){};
819 watermarks->metric = metric;
820 watermarks->interval_us = interval_us;
821 watermarks->high = high;
822 watermarks->mid = mid;
823 watermarks->low = low;
824 return watermarks;
825}
826
827struct damos_sysfs_wmark_metric_name {
828 enum damos_wmark_metric metric;
829 char *name;
830};
831
832static const struct damos_sysfs_wmark_metric_name
833damos_sysfs_wmark_metric_names[] = {
834 {
835 .metric = DAMOS_WMARK_NONE,
836 .name = "none",
837 },
838 {
839 .metric = DAMOS_WMARK_FREE_MEM_RATE,
840 .name = "free_mem_rate",
841 },
842};
843
844static ssize_t metric_show(struct kobject *kobj, struct kobj_attribute *attr,
845 char *buf)
846{
847 struct damon_sysfs_watermarks *watermarks = container_of(kobj,
848 struct damon_sysfs_watermarks, kobj);
849 int i;
850
851 for (i = 0; i < ARRAY_SIZE(damos_sysfs_wmark_metric_names); i++) {
852 const struct damos_sysfs_wmark_metric_name *metric_name;
853
854 metric_name = &damos_sysfs_wmark_metric_names[i];
855 if (metric_name->metric == watermarks->metric)
856 return sysfs_emit(buf, fmt: "%s\n", metric_name->name);
857 }
858 return -EINVAL;
859}
860
861static ssize_t metric_store(struct kobject *kobj, struct kobj_attribute *attr,
862 const char *buf, size_t count)
863{
864 struct damon_sysfs_watermarks *watermarks = container_of(kobj,
865 struct damon_sysfs_watermarks, kobj);
866 int i;
867
868 for (i = 0; i < ARRAY_SIZE(damos_sysfs_wmark_metric_names); i++) {
869 const struct damos_sysfs_wmark_metric_name *metric_name;
870
871 metric_name = &damos_sysfs_wmark_metric_names[i];
872 if (sysfs_streq(s1: buf, s2: metric_name->name)) {
873 watermarks->metric = metric_name->metric;
874 return count;
875 }
876 }
877 return -EINVAL;
878}
879
880static ssize_t interval_us_show(struct kobject *kobj,
881 struct kobj_attribute *attr, char *buf)
882{
883 struct damon_sysfs_watermarks *watermarks = container_of(kobj,
884 struct damon_sysfs_watermarks, kobj);
885
886 return sysfs_emit(buf, fmt: "%lu\n", watermarks->interval_us);
887}
888
889static ssize_t interval_us_store(struct kobject *kobj,
890 struct kobj_attribute *attr, const char *buf, size_t count)
891{
892 struct damon_sysfs_watermarks *watermarks = container_of(kobj,
893 struct damon_sysfs_watermarks, kobj);
894 int err = kstrtoul(s: buf, base: 0, res: &watermarks->interval_us);
895
896 return err ? err : count;
897}
898
899static ssize_t high_show(struct kobject *kobj,
900 struct kobj_attribute *attr, char *buf)
901{
902 struct damon_sysfs_watermarks *watermarks = container_of(kobj,
903 struct damon_sysfs_watermarks, kobj);
904
905 return sysfs_emit(buf, fmt: "%lu\n", watermarks->high);
906}
907
908static ssize_t high_store(struct kobject *kobj,
909 struct kobj_attribute *attr, const char *buf, size_t count)
910{
911 struct damon_sysfs_watermarks *watermarks = container_of(kobj,
912 struct damon_sysfs_watermarks, kobj);
913 int err = kstrtoul(s: buf, base: 0, res: &watermarks->high);
914
915 return err ? err : count;
916}
917
918static ssize_t mid_show(struct kobject *kobj,
919 struct kobj_attribute *attr, char *buf)
920{
921 struct damon_sysfs_watermarks *watermarks = container_of(kobj,
922 struct damon_sysfs_watermarks, kobj);
923
924 return sysfs_emit(buf, fmt: "%lu\n", watermarks->mid);
925}
926
927static ssize_t mid_store(struct kobject *kobj,
928 struct kobj_attribute *attr, const char *buf, size_t count)
929{
930 struct damon_sysfs_watermarks *watermarks = container_of(kobj,
931 struct damon_sysfs_watermarks, kobj);
932 int err = kstrtoul(s: buf, base: 0, res: &watermarks->mid);
933
934 return err ? err : count;
935}
936
937static ssize_t low_show(struct kobject *kobj,
938 struct kobj_attribute *attr, char *buf)
939{
940 struct damon_sysfs_watermarks *watermarks = container_of(kobj,
941 struct damon_sysfs_watermarks, kobj);
942
943 return sysfs_emit(buf, fmt: "%lu\n", watermarks->low);
944}
945
946static ssize_t low_store(struct kobject *kobj,
947 struct kobj_attribute *attr, const char *buf, size_t count)
948{
949 struct damon_sysfs_watermarks *watermarks = container_of(kobj,
950 struct damon_sysfs_watermarks, kobj);
951 int err = kstrtoul(s: buf, base: 0, res: &watermarks->low);
952
953 return err ? err : count;
954}
955
956static void damon_sysfs_watermarks_release(struct kobject *kobj)
957{
958 kfree(container_of(kobj, struct damon_sysfs_watermarks, kobj));
959}
960
961static struct kobj_attribute damon_sysfs_watermarks_metric_attr =
962 __ATTR_RW_MODE(metric, 0600);
963
964static struct kobj_attribute damon_sysfs_watermarks_interval_us_attr =
965 __ATTR_RW_MODE(interval_us, 0600);
966
967static struct kobj_attribute damon_sysfs_watermarks_high_attr =
968 __ATTR_RW_MODE(high, 0600);
969
970static struct kobj_attribute damon_sysfs_watermarks_mid_attr =
971 __ATTR_RW_MODE(mid, 0600);
972
973static struct kobj_attribute damon_sysfs_watermarks_low_attr =
974 __ATTR_RW_MODE(low, 0600);
975
976static struct attribute *damon_sysfs_watermarks_attrs[] = {
977 &damon_sysfs_watermarks_metric_attr.attr,
978 &damon_sysfs_watermarks_interval_us_attr.attr,
979 &damon_sysfs_watermarks_high_attr.attr,
980 &damon_sysfs_watermarks_mid_attr.attr,
981 &damon_sysfs_watermarks_low_attr.attr,
982 NULL,
983};
984ATTRIBUTE_GROUPS(damon_sysfs_watermarks);
985
986static const struct kobj_type damon_sysfs_watermarks_ktype = {
987 .release = damon_sysfs_watermarks_release,
988 .sysfs_ops = &kobj_sysfs_ops,
989 .default_groups = damon_sysfs_watermarks_groups,
990};
991
992/*
993 * quota goal directory
994 */
995
996struct damos_sysfs_quota_goal {
997 struct kobject kobj;
998 enum damos_quota_goal_metric metric;
999 unsigned long target_value;
1000 unsigned long current_value;
1001 int nid;
1002 char *path;
1003};
1004
1005static struct damos_sysfs_quota_goal *damos_sysfs_quota_goal_alloc(void)
1006{
1007 return kzalloc(sizeof(struct damos_sysfs_quota_goal), GFP_KERNEL);
1008}
1009
1010struct damos_sysfs_qgoal_metric_name {
1011 enum damos_quota_goal_metric metric;
1012 char *name;
1013};
1014
1015static
1016struct damos_sysfs_qgoal_metric_name damos_sysfs_qgoal_metric_names[] = {
1017 {
1018 .metric = DAMOS_QUOTA_USER_INPUT,
1019 .name = "user_input",
1020 },
1021 {
1022 .metric = DAMOS_QUOTA_SOME_MEM_PSI_US,
1023 .name = "some_mem_psi_us",
1024 },
1025 {
1026 .metric = DAMOS_QUOTA_NODE_MEM_USED_BP,
1027 .name = "node_mem_used_bp",
1028 },
1029 {
1030 .metric = DAMOS_QUOTA_NODE_MEM_FREE_BP,
1031 .name = "node_mem_free_bp",
1032 },
1033 {
1034 .metric = DAMOS_QUOTA_NODE_MEMCG_USED_BP,
1035 .name = "node_memcg_used_bp",
1036 },
1037 {
1038 .metric = DAMOS_QUOTA_NODE_MEMCG_FREE_BP,
1039 .name = "node_memcg_free_bp",
1040 },
1041};
1042
1043static ssize_t target_metric_show(struct kobject *kobj,
1044 struct kobj_attribute *attr, char *buf)
1045{
1046 struct damos_sysfs_quota_goal *goal = container_of(kobj,
1047 struct damos_sysfs_quota_goal, kobj);
1048 int i;
1049
1050 for (i = 0; i < ARRAY_SIZE(damos_sysfs_qgoal_metric_names); i++) {
1051 struct damos_sysfs_qgoal_metric_name *metric_name;
1052
1053 metric_name = &damos_sysfs_qgoal_metric_names[i];
1054 if (metric_name->metric == goal->metric)
1055 return sysfs_emit(buf, fmt: "%s\n", metric_name->name);
1056 }
1057 return -EINVAL;
1058}
1059
1060static ssize_t target_metric_store(struct kobject *kobj,
1061 struct kobj_attribute *attr, const char *buf, size_t count)
1062{
1063 struct damos_sysfs_quota_goal *goal = container_of(kobj,
1064 struct damos_sysfs_quota_goal, kobj);
1065 int i;
1066
1067 for (i = 0; i < ARRAY_SIZE(damos_sysfs_qgoal_metric_names); i++) {
1068 struct damos_sysfs_qgoal_metric_name *metric_name;
1069
1070 metric_name = &damos_sysfs_qgoal_metric_names[i];
1071 if (sysfs_streq(s1: buf, s2: metric_name->name)) {
1072 goal->metric = metric_name->metric;
1073 return count;
1074 }
1075 }
1076 return -EINVAL;
1077}
1078
1079static ssize_t target_value_show(struct kobject *kobj,
1080 struct kobj_attribute *attr, char *buf)
1081{
1082 struct damos_sysfs_quota_goal *goal = container_of(kobj, struct
1083 damos_sysfs_quota_goal, kobj);
1084
1085 return sysfs_emit(buf, fmt: "%lu\n", goal->target_value);
1086}
1087
1088static ssize_t target_value_store(struct kobject *kobj,
1089 struct kobj_attribute *attr, const char *buf, size_t count)
1090{
1091 struct damos_sysfs_quota_goal *goal = container_of(kobj, struct
1092 damos_sysfs_quota_goal, kobj);
1093 int err = kstrtoul(s: buf, base: 0, res: &goal->target_value);
1094
1095 return err ? err : count;
1096}
1097
1098static ssize_t current_value_show(struct kobject *kobj,
1099 struct kobj_attribute *attr, char *buf)
1100{
1101 struct damos_sysfs_quota_goal *goal = container_of(kobj, struct
1102 damos_sysfs_quota_goal, kobj);
1103
1104 return sysfs_emit(buf, fmt: "%lu\n", goal->current_value);
1105}
1106
1107static ssize_t current_value_store(struct kobject *kobj,
1108 struct kobj_attribute *attr, const char *buf, size_t count)
1109{
1110 struct damos_sysfs_quota_goal *goal = container_of(kobj, struct
1111 damos_sysfs_quota_goal, kobj);
1112 int err = kstrtoul(s: buf, base: 0, res: &goal->current_value);
1113
1114 /* feed callback should check existence of this file and read value */
1115 return err ? err : count;
1116}
1117
1118static ssize_t nid_show(struct kobject *kobj,
1119 struct kobj_attribute *attr, char *buf)
1120{
1121 struct damos_sysfs_quota_goal *goal = container_of(kobj, struct
1122 damos_sysfs_quota_goal, kobj);
1123
1124
1125 return sysfs_emit(buf, fmt: "%d\n", goal->nid);
1126}
1127
1128static ssize_t nid_store(struct kobject *kobj,
1129 struct kobj_attribute *attr, const char *buf, size_t count)
1130{
1131 struct damos_sysfs_quota_goal *goal = container_of(kobj, struct
1132 damos_sysfs_quota_goal, kobj);
1133 int err = kstrtoint(s: buf, base: 0, res: &goal->nid);
1134
1135 /* feed callback should check existence of this file and read value */
1136 return err ? err : count;
1137}
1138
1139static ssize_t path_show(struct kobject *kobj,
1140 struct kobj_attribute *attr, char *buf)
1141{
1142 struct damos_sysfs_quota_goal *goal = container_of(kobj,
1143 struct damos_sysfs_quota_goal, kobj);
1144
1145 return sysfs_emit(buf, fmt: "%s\n", goal->path ? goal->path : "");
1146}
1147
1148static ssize_t path_store(struct kobject *kobj,
1149 struct kobj_attribute *attr, const char *buf, size_t count)
1150{
1151 struct damos_sysfs_quota_goal *goal = container_of(kobj,
1152 struct damos_sysfs_quota_goal, kobj);
1153 char *path = kmalloc_array(size_add(count, 1), sizeof(*path),
1154 GFP_KERNEL);
1155
1156 if (!path)
1157 return -ENOMEM;
1158
1159 strscpy(path, buf, count + 1);
1160 kfree(objp: goal->path);
1161 goal->path = path;
1162 return count;
1163}
1164
1165static void damos_sysfs_quota_goal_release(struct kobject *kobj)
1166{
1167 struct damos_sysfs_quota_goal *goal = container_of(kobj,
1168 struct damos_sysfs_quota_goal, kobj);
1169
1170 kfree(objp: goal->path);
1171 kfree(objp: goal);
1172}
1173
1174static struct kobj_attribute damos_sysfs_quota_goal_target_metric_attr =
1175 __ATTR_RW_MODE(target_metric, 0600);
1176
1177static struct kobj_attribute damos_sysfs_quota_goal_target_value_attr =
1178 __ATTR_RW_MODE(target_value, 0600);
1179
1180static struct kobj_attribute damos_sysfs_quota_goal_current_value_attr =
1181 __ATTR_RW_MODE(current_value, 0600);
1182
1183static struct kobj_attribute damos_sysfs_quota_goal_nid_attr =
1184 __ATTR_RW_MODE(nid, 0600);
1185
1186static struct kobj_attribute damos_sysfs_quota_goal_path_attr =
1187 __ATTR_RW_MODE(path, 0600);
1188
1189static struct attribute *damos_sysfs_quota_goal_attrs[] = {
1190 &damos_sysfs_quota_goal_target_metric_attr.attr,
1191 &damos_sysfs_quota_goal_target_value_attr.attr,
1192 &damos_sysfs_quota_goal_current_value_attr.attr,
1193 &damos_sysfs_quota_goal_nid_attr.attr,
1194 &damos_sysfs_quota_goal_path_attr.attr,
1195 NULL,
1196};
1197ATTRIBUTE_GROUPS(damos_sysfs_quota_goal);
1198
1199static const struct kobj_type damos_sysfs_quota_goal_ktype = {
1200 .release = damos_sysfs_quota_goal_release,
1201 .sysfs_ops = &kobj_sysfs_ops,
1202 .default_groups = damos_sysfs_quota_goal_groups,
1203};
1204
1205/*
1206 * quota goals directory
1207 */
1208
1209struct damos_sysfs_quota_goals {
1210 struct kobject kobj;
1211 struct damos_sysfs_quota_goal **goals_arr; /* counted by nr */
1212 int nr;
1213};
1214
1215static struct damos_sysfs_quota_goals *damos_sysfs_quota_goals_alloc(void)
1216{
1217 return kzalloc(sizeof(struct damos_sysfs_quota_goals), GFP_KERNEL);
1218}
1219
1220static void damos_sysfs_quota_goals_rm_dirs(
1221 struct damos_sysfs_quota_goals *goals)
1222{
1223 struct damos_sysfs_quota_goal **goals_arr = goals->goals_arr;
1224 int i;
1225
1226 for (i = 0; i < goals->nr; i++)
1227 kobject_put(kobj: &goals_arr[i]->kobj);
1228 goals->nr = 0;
1229 kfree(objp: goals_arr);
1230 goals->goals_arr = NULL;
1231}
1232
1233static int damos_sysfs_quota_goals_add_dirs(
1234 struct damos_sysfs_quota_goals *goals, int nr_goals)
1235{
1236 struct damos_sysfs_quota_goal **goals_arr, *goal;
1237 int err, i;
1238
1239 damos_sysfs_quota_goals_rm_dirs(goals);
1240 if (!nr_goals)
1241 return 0;
1242
1243 goals_arr = kmalloc_array(nr_goals, sizeof(*goals_arr),
1244 GFP_KERNEL | __GFP_NOWARN);
1245 if (!goals_arr)
1246 return -ENOMEM;
1247 goals->goals_arr = goals_arr;
1248
1249 for (i = 0; i < nr_goals; i++) {
1250 goal = damos_sysfs_quota_goal_alloc();
1251 if (!goal) {
1252 damos_sysfs_quota_goals_rm_dirs(goals);
1253 return -ENOMEM;
1254 }
1255
1256 err = kobject_init_and_add(kobj: &goal->kobj,
1257 ktype: &damos_sysfs_quota_goal_ktype, parent: &goals->kobj,
1258 fmt: "%d", i);
1259 if (err) {
1260 kobject_put(kobj: &goal->kobj);
1261 damos_sysfs_quota_goals_rm_dirs(goals);
1262 return err;
1263 }
1264
1265 goals_arr[i] = goal;
1266 goals->nr++;
1267 }
1268 return 0;
1269}
1270
1271static ssize_t nr_goals_show(struct kobject *kobj,
1272 struct kobj_attribute *attr, char *buf)
1273{
1274 struct damos_sysfs_quota_goals *goals = container_of(kobj,
1275 struct damos_sysfs_quota_goals, kobj);
1276
1277 return sysfs_emit(buf, fmt: "%d\n", goals->nr);
1278}
1279
1280static ssize_t nr_goals_store(struct kobject *kobj,
1281 struct kobj_attribute *attr, const char *buf, size_t count)
1282{
1283 struct damos_sysfs_quota_goals *goals;
1284 int nr, err = kstrtoint(s: buf, base: 0, res: &nr);
1285
1286 if (err)
1287 return err;
1288 if (nr < 0)
1289 return -EINVAL;
1290
1291 goals = container_of(kobj, struct damos_sysfs_quota_goals, kobj);
1292
1293 if (!mutex_trylock(&damon_sysfs_lock))
1294 return -EBUSY;
1295 err = damos_sysfs_quota_goals_add_dirs(goals, nr_goals: nr);
1296 mutex_unlock(lock: &damon_sysfs_lock);
1297 if (err)
1298 return err;
1299
1300 return count;
1301}
1302
1303static void damos_sysfs_quota_goals_release(struct kobject *kobj)
1304{
1305 kfree(container_of(kobj, struct damos_sysfs_quota_goals, kobj));
1306}
1307
1308static struct kobj_attribute damos_sysfs_quota_goals_nr_attr =
1309 __ATTR_RW_MODE(nr_goals, 0600);
1310
1311static struct attribute *damos_sysfs_quota_goals_attrs[] = {
1312 &damos_sysfs_quota_goals_nr_attr.attr,
1313 NULL,
1314};
1315ATTRIBUTE_GROUPS(damos_sysfs_quota_goals);
1316
1317static const struct kobj_type damos_sysfs_quota_goals_ktype = {
1318 .release = damos_sysfs_quota_goals_release,
1319 .sysfs_ops = &kobj_sysfs_ops,
1320 .default_groups = damos_sysfs_quota_goals_groups,
1321};
1322
1323/*
1324 * scheme/weights directory
1325 */
1326
1327struct damon_sysfs_weights {
1328 struct kobject kobj;
1329 unsigned int sz;
1330 unsigned int nr_accesses;
1331 unsigned int age;
1332};
1333
1334static struct damon_sysfs_weights *damon_sysfs_weights_alloc(unsigned int sz,
1335 unsigned int nr_accesses, unsigned int age)
1336{
1337 struct damon_sysfs_weights *weights = kmalloc(sizeof(*weights),
1338 GFP_KERNEL);
1339
1340 if (!weights)
1341 return NULL;
1342 weights->kobj = (struct kobject){};
1343 weights->sz = sz;
1344 weights->nr_accesses = nr_accesses;
1345 weights->age = age;
1346 return weights;
1347}
1348
1349static ssize_t sz_permil_show(struct kobject *kobj,
1350 struct kobj_attribute *attr, char *buf)
1351{
1352 struct damon_sysfs_weights *weights = container_of(kobj,
1353 struct damon_sysfs_weights, kobj);
1354
1355 return sysfs_emit(buf, fmt: "%u\n", weights->sz);
1356}
1357
1358static ssize_t sz_permil_store(struct kobject *kobj,
1359 struct kobj_attribute *attr, const char *buf, size_t count)
1360{
1361 struct damon_sysfs_weights *weights = container_of(kobj,
1362 struct damon_sysfs_weights, kobj);
1363 int err = kstrtouint(s: buf, base: 0, res: &weights->sz);
1364
1365 return err ? err : count;
1366}
1367
1368static ssize_t nr_accesses_permil_show(struct kobject *kobj,
1369 struct kobj_attribute *attr, char *buf)
1370{
1371 struct damon_sysfs_weights *weights = container_of(kobj,
1372 struct damon_sysfs_weights, kobj);
1373
1374 return sysfs_emit(buf, fmt: "%u\n", weights->nr_accesses);
1375}
1376
1377static ssize_t nr_accesses_permil_store(struct kobject *kobj,
1378 struct kobj_attribute *attr, const char *buf, size_t count)
1379{
1380 struct damon_sysfs_weights *weights = container_of(kobj,
1381 struct damon_sysfs_weights, kobj);
1382 int err = kstrtouint(s: buf, base: 0, res: &weights->nr_accesses);
1383
1384 return err ? err : count;
1385}
1386
1387static ssize_t age_permil_show(struct kobject *kobj,
1388 struct kobj_attribute *attr, char *buf)
1389{
1390 struct damon_sysfs_weights *weights = container_of(kobj,
1391 struct damon_sysfs_weights, kobj);
1392
1393 return sysfs_emit(buf, fmt: "%u\n", weights->age);
1394}
1395
1396static ssize_t age_permil_store(struct kobject *kobj,
1397 struct kobj_attribute *attr, const char *buf, size_t count)
1398{
1399 struct damon_sysfs_weights *weights = container_of(kobj,
1400 struct damon_sysfs_weights, kobj);
1401 int err = kstrtouint(s: buf, base: 0, res: &weights->age);
1402
1403 return err ? err : count;
1404}
1405
1406static void damon_sysfs_weights_release(struct kobject *kobj)
1407{
1408 kfree(container_of(kobj, struct damon_sysfs_weights, kobj));
1409}
1410
1411static struct kobj_attribute damon_sysfs_weights_sz_attr =
1412 __ATTR_RW_MODE(sz_permil, 0600);
1413
1414static struct kobj_attribute damon_sysfs_weights_nr_accesses_attr =
1415 __ATTR_RW_MODE(nr_accesses_permil, 0600);
1416
1417static struct kobj_attribute damon_sysfs_weights_age_attr =
1418 __ATTR_RW_MODE(age_permil, 0600);
1419
1420static struct attribute *damon_sysfs_weights_attrs[] = {
1421 &damon_sysfs_weights_sz_attr.attr,
1422 &damon_sysfs_weights_nr_accesses_attr.attr,
1423 &damon_sysfs_weights_age_attr.attr,
1424 NULL,
1425};
1426ATTRIBUTE_GROUPS(damon_sysfs_weights);
1427
1428static const struct kobj_type damon_sysfs_weights_ktype = {
1429 .release = damon_sysfs_weights_release,
1430 .sysfs_ops = &kobj_sysfs_ops,
1431 .default_groups = damon_sysfs_weights_groups,
1432};
1433
1434/*
1435 * quotas directory
1436 */
1437
1438struct damon_sysfs_quotas {
1439 struct kobject kobj;
1440 struct damon_sysfs_weights *weights;
1441 struct damos_sysfs_quota_goals *goals;
1442 unsigned long ms;
1443 unsigned long sz;
1444 unsigned long reset_interval_ms;
1445 unsigned long effective_sz; /* Effective size quota in bytes */
1446};
1447
1448static struct damon_sysfs_quotas *damon_sysfs_quotas_alloc(void)
1449{
1450 return kzalloc(sizeof(struct damon_sysfs_quotas), GFP_KERNEL);
1451}
1452
1453static int damon_sysfs_quotas_add_dirs(struct damon_sysfs_quotas *quotas)
1454{
1455 struct damon_sysfs_weights *weights;
1456 struct damos_sysfs_quota_goals *goals;
1457 int err;
1458
1459 weights = damon_sysfs_weights_alloc(sz: 0, nr_accesses: 0, age: 0);
1460 if (!weights)
1461 return -ENOMEM;
1462
1463 err = kobject_init_and_add(kobj: &weights->kobj, ktype: &damon_sysfs_weights_ktype,
1464 parent: &quotas->kobj, fmt: "weights");
1465 if (err) {
1466 kobject_put(kobj: &weights->kobj);
1467 return err;
1468 }
1469 quotas->weights = weights;
1470
1471 goals = damos_sysfs_quota_goals_alloc();
1472 if (!goals) {
1473 kobject_put(kobj: &weights->kobj);
1474 return -ENOMEM;
1475 }
1476 err = kobject_init_and_add(kobj: &goals->kobj,
1477 ktype: &damos_sysfs_quota_goals_ktype, parent: &quotas->kobj,
1478 fmt: "goals");
1479 if (err) {
1480 kobject_put(kobj: &weights->kobj);
1481 kobject_put(kobj: &goals->kobj);
1482 } else {
1483 quotas->goals = goals;
1484 }
1485
1486 return err;
1487}
1488
1489static void damon_sysfs_quotas_rm_dirs(struct damon_sysfs_quotas *quotas)
1490{
1491 kobject_put(kobj: &quotas->weights->kobj);
1492 damos_sysfs_quota_goals_rm_dirs(goals: quotas->goals);
1493 kobject_put(kobj: &quotas->goals->kobj);
1494}
1495
1496static ssize_t ms_show(struct kobject *kobj, struct kobj_attribute *attr,
1497 char *buf)
1498{
1499 struct damon_sysfs_quotas *quotas = container_of(kobj,
1500 struct damon_sysfs_quotas, kobj);
1501
1502 return sysfs_emit(buf, fmt: "%lu\n", quotas->ms);
1503}
1504
1505static ssize_t ms_store(struct kobject *kobj, struct kobj_attribute *attr,
1506 const char *buf, size_t count)
1507{
1508 struct damon_sysfs_quotas *quotas = container_of(kobj,
1509 struct damon_sysfs_quotas, kobj);
1510 int err = kstrtoul(s: buf, base: 0, res: &quotas->ms);
1511
1512 if (err)
1513 return -EINVAL;
1514 return count;
1515}
1516
1517static ssize_t bytes_show(struct kobject *kobj, struct kobj_attribute *attr,
1518 char *buf)
1519{
1520 struct damon_sysfs_quotas *quotas = container_of(kobj,
1521 struct damon_sysfs_quotas, kobj);
1522
1523 return sysfs_emit(buf, fmt: "%lu\n", quotas->sz);
1524}
1525
1526static ssize_t bytes_store(struct kobject *kobj,
1527 struct kobj_attribute *attr, const char *buf, size_t count)
1528{
1529 struct damon_sysfs_quotas *quotas = container_of(kobj,
1530 struct damon_sysfs_quotas, kobj);
1531 int err = kstrtoul(s: buf, base: 0, res: &quotas->sz);
1532
1533 if (err)
1534 return -EINVAL;
1535 return count;
1536}
1537
1538static ssize_t reset_interval_ms_show(struct kobject *kobj,
1539 struct kobj_attribute *attr, char *buf)
1540{
1541 struct damon_sysfs_quotas *quotas = container_of(kobj,
1542 struct damon_sysfs_quotas, kobj);
1543
1544 return sysfs_emit(buf, fmt: "%lu\n", quotas->reset_interval_ms);
1545}
1546
1547static ssize_t reset_interval_ms_store(struct kobject *kobj,
1548 struct kobj_attribute *attr, const char *buf, size_t count)
1549{
1550 struct damon_sysfs_quotas *quotas = container_of(kobj,
1551 struct damon_sysfs_quotas, kobj);
1552 int err = kstrtoul(s: buf, base: 0, res: &quotas->reset_interval_ms);
1553
1554 if (err)
1555 return -EINVAL;
1556 return count;
1557}
1558
1559static ssize_t effective_bytes_show(struct kobject *kobj,
1560 struct kobj_attribute *attr, char *buf)
1561{
1562 struct damon_sysfs_quotas *quotas = container_of(kobj,
1563 struct damon_sysfs_quotas, kobj);
1564
1565 return sysfs_emit(buf, fmt: "%lu\n", quotas->effective_sz);
1566}
1567
1568static void damon_sysfs_quotas_release(struct kobject *kobj)
1569{
1570 kfree(container_of(kobj, struct damon_sysfs_quotas, kobj));
1571}
1572
1573static struct kobj_attribute damon_sysfs_quotas_ms_attr =
1574 __ATTR_RW_MODE(ms, 0600);
1575
1576static struct kobj_attribute damon_sysfs_quotas_sz_attr =
1577 __ATTR_RW_MODE(bytes, 0600);
1578
1579static struct kobj_attribute damon_sysfs_quotas_reset_interval_ms_attr =
1580 __ATTR_RW_MODE(reset_interval_ms, 0600);
1581
1582static struct kobj_attribute damon_sysfs_quotas_effective_bytes_attr =
1583 __ATTR_RO_MODE(effective_bytes, 0400);
1584
1585static struct attribute *damon_sysfs_quotas_attrs[] = {
1586 &damon_sysfs_quotas_ms_attr.attr,
1587 &damon_sysfs_quotas_sz_attr.attr,
1588 &damon_sysfs_quotas_reset_interval_ms_attr.attr,
1589 &damon_sysfs_quotas_effective_bytes_attr.attr,
1590 NULL,
1591};
1592ATTRIBUTE_GROUPS(damon_sysfs_quotas);
1593
1594static const struct kobj_type damon_sysfs_quotas_ktype = {
1595 .release = damon_sysfs_quotas_release,
1596 .sysfs_ops = &kobj_sysfs_ops,
1597 .default_groups = damon_sysfs_quotas_groups,
1598};
1599
1600/*
1601 * access_pattern directory
1602 */
1603
1604struct damon_sysfs_access_pattern {
1605 struct kobject kobj;
1606 struct damon_sysfs_ul_range *sz;
1607 struct damon_sysfs_ul_range *nr_accesses;
1608 struct damon_sysfs_ul_range *age;
1609};
1610
1611static
1612struct damon_sysfs_access_pattern *damon_sysfs_access_pattern_alloc(void)
1613{
1614 struct damon_sysfs_access_pattern *access_pattern =
1615 kmalloc(sizeof(*access_pattern), GFP_KERNEL);
1616
1617 if (!access_pattern)
1618 return NULL;
1619 access_pattern->kobj = (struct kobject){};
1620 return access_pattern;
1621}
1622
1623static int damon_sysfs_access_pattern_add_range_dir(
1624 struct damon_sysfs_access_pattern *access_pattern,
1625 struct damon_sysfs_ul_range **range_dir_ptr,
1626 char *name)
1627{
1628 struct damon_sysfs_ul_range *range = damon_sysfs_ul_range_alloc(min: 0, max: 0);
1629 int err;
1630
1631 if (!range)
1632 return -ENOMEM;
1633 err = kobject_init_and_add(kobj: &range->kobj, ktype: &damon_sysfs_ul_range_ktype,
1634 parent: &access_pattern->kobj, fmt: "%s", name);
1635 if (err)
1636 kobject_put(kobj: &range->kobj);
1637 else
1638 *range_dir_ptr = range;
1639 return err;
1640}
1641
1642static int damon_sysfs_access_pattern_add_dirs(
1643 struct damon_sysfs_access_pattern *access_pattern)
1644{
1645 int err;
1646
1647 err = damon_sysfs_access_pattern_add_range_dir(access_pattern,
1648 range_dir_ptr: &access_pattern->sz, name: "sz");
1649 if (err)
1650 goto put_sz_out;
1651
1652 err = damon_sysfs_access_pattern_add_range_dir(access_pattern,
1653 range_dir_ptr: &access_pattern->nr_accesses, name: "nr_accesses");
1654 if (err)
1655 goto put_nr_accesses_sz_out;
1656
1657 err = damon_sysfs_access_pattern_add_range_dir(access_pattern,
1658 range_dir_ptr: &access_pattern->age, name: "age");
1659 if (err)
1660 goto put_age_nr_accesses_sz_out;
1661 return 0;
1662
1663put_age_nr_accesses_sz_out:
1664 kobject_put(kobj: &access_pattern->age->kobj);
1665 access_pattern->age = NULL;
1666put_nr_accesses_sz_out:
1667 kobject_put(kobj: &access_pattern->nr_accesses->kobj);
1668 access_pattern->nr_accesses = NULL;
1669put_sz_out:
1670 kobject_put(kobj: &access_pattern->sz->kobj);
1671 access_pattern->sz = NULL;
1672 return err;
1673}
1674
1675static void damon_sysfs_access_pattern_rm_dirs(
1676 struct damon_sysfs_access_pattern *access_pattern)
1677{
1678 kobject_put(kobj: &access_pattern->sz->kobj);
1679 kobject_put(kobj: &access_pattern->nr_accesses->kobj);
1680 kobject_put(kobj: &access_pattern->age->kobj);
1681}
1682
1683static void damon_sysfs_access_pattern_release(struct kobject *kobj)
1684{
1685 kfree(container_of(kobj, struct damon_sysfs_access_pattern, kobj));
1686}
1687
1688static struct attribute *damon_sysfs_access_pattern_attrs[] = {
1689 NULL,
1690};
1691ATTRIBUTE_GROUPS(damon_sysfs_access_pattern);
1692
1693static const struct kobj_type damon_sysfs_access_pattern_ktype = {
1694 .release = damon_sysfs_access_pattern_release,
1695 .sysfs_ops = &kobj_sysfs_ops,
1696 .default_groups = damon_sysfs_access_pattern_groups,
1697};
1698
1699/*
1700 * dest (action destination) directory
1701 */
1702
1703struct damos_sysfs_dest {
1704 struct kobject kobj;
1705 unsigned int id;
1706 unsigned int weight;
1707};
1708
1709static struct damos_sysfs_dest *damos_sysfs_dest_alloc(void)
1710{
1711 return kzalloc(sizeof(struct damos_sysfs_dest), GFP_KERNEL);
1712}
1713
1714static ssize_t id_show(
1715 struct kobject *kobj, struct kobj_attribute *attr, char *buf)
1716{
1717 struct damos_sysfs_dest *dest = container_of(kobj,
1718 struct damos_sysfs_dest, kobj);
1719
1720 return sysfs_emit(buf, fmt: "%u\n", dest->id);
1721}
1722
1723static ssize_t id_store(struct kobject *kobj,
1724 struct kobj_attribute *attr, const char *buf, size_t count)
1725{
1726 struct damos_sysfs_dest *dest = container_of(kobj,
1727 struct damos_sysfs_dest, kobj);
1728 int err = kstrtouint(s: buf, base: 0, res: &dest->id);
1729
1730 return err ? err : count;
1731}
1732
1733static ssize_t weight_show(
1734 struct kobject *kobj, struct kobj_attribute *attr, char *buf)
1735{
1736 struct damos_sysfs_dest *dest = container_of(kobj,
1737 struct damos_sysfs_dest, kobj);
1738
1739 return sysfs_emit(buf, fmt: "%u\n", dest->weight);
1740}
1741
1742static ssize_t weight_store(struct kobject *kobj,
1743 struct kobj_attribute *attr, const char *buf, size_t count)
1744{
1745 struct damos_sysfs_dest *dest = container_of(kobj,
1746 struct damos_sysfs_dest, kobj);
1747 int err = kstrtouint(s: buf, base: 0, res: &dest->weight);
1748
1749 return err ? err : count;
1750}
1751
1752static void damos_sysfs_dest_release(struct kobject *kobj)
1753{
1754 struct damos_sysfs_dest *dest = container_of(kobj,
1755 struct damos_sysfs_dest, kobj);
1756 kfree(objp: dest);
1757}
1758
1759static struct kobj_attribute damos_sysfs_dest_id_attr =
1760 __ATTR_RW_MODE(id, 0600);
1761
1762static struct kobj_attribute damos_sysfs_dest_weight_attr =
1763 __ATTR_RW_MODE(weight, 0600);
1764
1765static struct attribute *damos_sysfs_dest_attrs[] = {
1766 &damos_sysfs_dest_id_attr.attr,
1767 &damos_sysfs_dest_weight_attr.attr,
1768 NULL,
1769};
1770ATTRIBUTE_GROUPS(damos_sysfs_dest);
1771
1772static const struct kobj_type damos_sysfs_dest_ktype = {
1773 .release = damos_sysfs_dest_release,
1774 .sysfs_ops = &kobj_sysfs_ops,
1775 .default_groups = damos_sysfs_dest_groups,
1776};
1777
1778/*
1779 * dests (action destinations) directory
1780 */
1781
1782struct damos_sysfs_dests {
1783 struct kobject kobj;
1784 struct damos_sysfs_dest **dests_arr;
1785 int nr;
1786};
1787
1788static struct damos_sysfs_dests *
1789damos_sysfs_dests_alloc(void)
1790{
1791 return kzalloc(sizeof(struct damos_sysfs_dests), GFP_KERNEL);
1792}
1793
1794static void damos_sysfs_dests_rm_dirs(
1795 struct damos_sysfs_dests *dests)
1796{
1797 struct damos_sysfs_dest **dests_arr = dests->dests_arr;
1798 int i;
1799
1800 for (i = 0; i < dests->nr; i++)
1801 kobject_put(kobj: &dests_arr[i]->kobj);
1802 dests->nr = 0;
1803 kfree(objp: dests_arr);
1804 dests->dests_arr = NULL;
1805}
1806
1807static int damos_sysfs_dests_add_dirs(
1808 struct damos_sysfs_dests *dests, int nr_dests)
1809{
1810 struct damos_sysfs_dest **dests_arr, *dest;
1811 int err, i;
1812
1813 damos_sysfs_dests_rm_dirs(dests);
1814 if (!nr_dests)
1815 return 0;
1816
1817 dests_arr = kmalloc_array(nr_dests, sizeof(*dests_arr),
1818 GFP_KERNEL | __GFP_NOWARN);
1819 if (!dests_arr)
1820 return -ENOMEM;
1821 dests->dests_arr = dests_arr;
1822
1823 for (i = 0; i < nr_dests; i++) {
1824 dest = damos_sysfs_dest_alloc();
1825 if (!dest) {
1826 damos_sysfs_dests_rm_dirs(dests);
1827 return -ENOMEM;
1828 }
1829
1830 err = kobject_init_and_add(kobj: &dest->kobj,
1831 ktype: &damos_sysfs_dest_ktype,
1832 parent: &dests->kobj, fmt: "%d", i);
1833 if (err) {
1834 kobject_put(kobj: &dest->kobj);
1835 damos_sysfs_dests_rm_dirs(dests);
1836 return err;
1837 }
1838
1839 dests_arr[i] = dest;
1840 dests->nr++;
1841 }
1842 return 0;
1843}
1844
1845static ssize_t nr_dests_show(struct kobject *kobj,
1846 struct kobj_attribute *attr, char *buf)
1847{
1848 struct damos_sysfs_dests *dests = container_of(kobj,
1849 struct damos_sysfs_dests, kobj);
1850
1851 return sysfs_emit(buf, fmt: "%d\n", dests->nr);
1852}
1853
1854static ssize_t nr_dests_store(struct kobject *kobj,
1855 struct kobj_attribute *attr, const char *buf, size_t count)
1856{
1857 struct damos_sysfs_dests *dests;
1858 int nr, err = kstrtoint(s: buf, base: 0, res: &nr);
1859
1860 if (err)
1861 return err;
1862 if (nr < 0)
1863 return -EINVAL;
1864
1865 dests = container_of(kobj, struct damos_sysfs_dests, kobj);
1866
1867 if (!mutex_trylock(&damon_sysfs_lock))
1868 return -EBUSY;
1869 err = damos_sysfs_dests_add_dirs(dests, nr_dests: nr);
1870 mutex_unlock(lock: &damon_sysfs_lock);
1871 if (err)
1872 return err;
1873
1874 return count;
1875}
1876
1877static void damos_sysfs_dests_release(struct kobject *kobj)
1878{
1879 kfree(container_of(kobj, struct damos_sysfs_dests, kobj));
1880}
1881
1882static struct kobj_attribute damos_sysfs_dests_nr_attr =
1883 __ATTR_RW_MODE(nr_dests, 0600);
1884
1885static struct attribute *damos_sysfs_dests_attrs[] = {
1886 &damos_sysfs_dests_nr_attr.attr,
1887 NULL,
1888};
1889ATTRIBUTE_GROUPS(damos_sysfs_dests);
1890
1891static const struct kobj_type damos_sysfs_dests_ktype = {
1892 .release = damos_sysfs_dests_release,
1893 .sysfs_ops = &kobj_sysfs_ops,
1894 .default_groups = damos_sysfs_dests_groups,
1895};
1896
1897/*
1898 * scheme directory
1899 */
1900
1901struct damon_sysfs_scheme {
1902 struct kobject kobj;
1903 enum damos_action action;
1904 struct damon_sysfs_access_pattern *access_pattern;
1905 unsigned long apply_interval_us;
1906 struct damon_sysfs_quotas *quotas;
1907 struct damon_sysfs_watermarks *watermarks;
1908 struct damon_sysfs_scheme_filters *core_filters;
1909 struct damon_sysfs_scheme_filters *ops_filters;
1910 struct damon_sysfs_scheme_filters *filters;
1911 struct damon_sysfs_stats *stats;
1912 struct damon_sysfs_scheme_regions *tried_regions;
1913 int target_nid;
1914 struct damos_sysfs_dests *dests;
1915};
1916
1917struct damos_sysfs_action_name {
1918 enum damos_action action;
1919 char *name;
1920};
1921
1922static struct damos_sysfs_action_name damos_sysfs_action_names[] = {
1923 {
1924 .action = DAMOS_WILLNEED,
1925 .name = "willneed",
1926 },
1927 {
1928 .action = DAMOS_COLD,
1929 .name = "cold",
1930 },
1931 {
1932 .action = DAMOS_PAGEOUT,
1933 .name = "pageout",
1934 },
1935 {
1936 .action = DAMOS_HUGEPAGE,
1937 .name = "hugepage",
1938 },
1939 {
1940 .action = DAMOS_NOHUGEPAGE,
1941 .name = "nohugepage",
1942 },
1943 {
1944 .action = DAMOS_LRU_PRIO,
1945 .name = "lru_prio",
1946 },
1947 {
1948 .action = DAMOS_LRU_DEPRIO,
1949 .name = "lru_deprio",
1950 },
1951 {
1952 .action = DAMOS_MIGRATE_HOT,
1953 .name = "migrate_hot",
1954 },
1955 {
1956 .action = DAMOS_MIGRATE_COLD,
1957 .name = "migrate_cold",
1958 },
1959 {
1960 .action = DAMOS_STAT,
1961 .name = "stat",
1962 },
1963};
1964
1965static struct damon_sysfs_scheme *damon_sysfs_scheme_alloc(
1966 enum damos_action action, unsigned long apply_interval_us)
1967{
1968 struct damon_sysfs_scheme *scheme = kmalloc(sizeof(*scheme),
1969 GFP_KERNEL);
1970
1971 if (!scheme)
1972 return NULL;
1973 scheme->kobj = (struct kobject){};
1974 scheme->action = action;
1975 scheme->apply_interval_us = apply_interval_us;
1976 scheme->target_nid = NUMA_NO_NODE;
1977 return scheme;
1978}
1979
1980static int damon_sysfs_scheme_set_access_pattern(
1981 struct damon_sysfs_scheme *scheme)
1982{
1983 struct damon_sysfs_access_pattern *access_pattern;
1984 int err;
1985
1986 access_pattern = damon_sysfs_access_pattern_alloc();
1987 if (!access_pattern)
1988 return -ENOMEM;
1989 err = kobject_init_and_add(kobj: &access_pattern->kobj,
1990 ktype: &damon_sysfs_access_pattern_ktype, parent: &scheme->kobj,
1991 fmt: "access_pattern");
1992 if (err)
1993 goto out;
1994 err = damon_sysfs_access_pattern_add_dirs(access_pattern);
1995 if (err)
1996 goto out;
1997 scheme->access_pattern = access_pattern;
1998 return 0;
1999
2000out:
2001 kobject_put(kobj: &access_pattern->kobj);
2002 return err;
2003}
2004
2005static int damos_sysfs_set_dests(struct damon_sysfs_scheme *scheme)
2006{
2007 struct damos_sysfs_dests *dests = damos_sysfs_dests_alloc();
2008 int err;
2009
2010 if (!dests)
2011 return -ENOMEM;
2012 err = kobject_init_and_add(kobj: &dests->kobj, ktype: &damos_sysfs_dests_ktype,
2013 parent: &scheme->kobj, fmt: "dests");
2014 if (err)
2015 kobject_put(kobj: &dests->kobj);
2016 else
2017 scheme->dests = dests;
2018 return err;
2019}
2020
2021static int damon_sysfs_scheme_set_quotas(struct damon_sysfs_scheme *scheme)
2022{
2023 struct damon_sysfs_quotas *quotas = damon_sysfs_quotas_alloc();
2024 int err;
2025
2026 if (!quotas)
2027 return -ENOMEM;
2028 err = kobject_init_and_add(kobj: &quotas->kobj, ktype: &damon_sysfs_quotas_ktype,
2029 parent: &scheme->kobj, fmt: "quotas");
2030 if (err)
2031 goto out;
2032 err = damon_sysfs_quotas_add_dirs(quotas);
2033 if (err)
2034 goto out;
2035 scheme->quotas = quotas;
2036 return 0;
2037
2038out:
2039 kobject_put(kobj: &quotas->kobj);
2040 return err;
2041}
2042
2043static int damon_sysfs_scheme_set_watermarks(struct damon_sysfs_scheme *scheme)
2044{
2045 struct damon_sysfs_watermarks *watermarks =
2046 damon_sysfs_watermarks_alloc(metric: DAMOS_WMARK_NONE, interval_us: 0, high: 0, mid: 0, low: 0);
2047 int err;
2048
2049 if (!watermarks)
2050 return -ENOMEM;
2051 err = kobject_init_and_add(kobj: &watermarks->kobj,
2052 ktype: &damon_sysfs_watermarks_ktype, parent: &scheme->kobj,
2053 fmt: "watermarks");
2054 if (err)
2055 kobject_put(kobj: &watermarks->kobj);
2056 else
2057 scheme->watermarks = watermarks;
2058 return err;
2059}
2060
2061static int damon_sysfs_scheme_set_filters(struct damon_sysfs_scheme *scheme,
2062 enum damos_sysfs_filter_handle_layer layer, const char *name,
2063 struct damon_sysfs_scheme_filters **filters_ptr)
2064{
2065 struct damon_sysfs_scheme_filters *filters =
2066 damon_sysfs_scheme_filters_alloc(layer);
2067 int err;
2068
2069 if (!filters)
2070 return -ENOMEM;
2071 err = kobject_init_and_add(kobj: &filters->kobj,
2072 ktype: &damon_sysfs_scheme_filters_ktype, parent: &scheme->kobj,
2073 fmt: "%s", name);
2074 if (err)
2075 kobject_put(kobj: &filters->kobj);
2076 else
2077 *filters_ptr = filters;
2078 return err;
2079}
2080
2081static int damos_sysfs_set_filter_dirs(struct damon_sysfs_scheme *scheme)
2082{
2083 int err;
2084
2085 err = damon_sysfs_scheme_set_filters(scheme,
2086 layer: DAMOS_SYSFS_FILTER_HANDLE_LAYER_BOTH, name: "filters",
2087 filters_ptr: &scheme->filters);
2088 if (err)
2089 return err;
2090 err = damon_sysfs_scheme_set_filters(scheme,
2091 layer: DAMOS_SYSFS_FILTER_HANDLE_LAYER_CORE, name: "core_filters",
2092 filters_ptr: &scheme->core_filters);
2093 if (err)
2094 goto put_filters_out;
2095 err = damon_sysfs_scheme_set_filters(scheme,
2096 layer: DAMOS_SYSFS_FILTER_HANDLE_LAYER_OPS, name: "ops_filters",
2097 filters_ptr: &scheme->ops_filters);
2098 if (err)
2099 goto put_core_filters_out;
2100 return 0;
2101
2102put_core_filters_out:
2103 kobject_put(kobj: &scheme->core_filters->kobj);
2104 scheme->core_filters = NULL;
2105put_filters_out:
2106 kobject_put(kobj: &scheme->filters->kobj);
2107 scheme->filters = NULL;
2108 return err;
2109}
2110
2111static int damon_sysfs_scheme_set_stats(struct damon_sysfs_scheme *scheme)
2112{
2113 struct damon_sysfs_stats *stats = damon_sysfs_stats_alloc();
2114 int err;
2115
2116 if (!stats)
2117 return -ENOMEM;
2118 err = kobject_init_and_add(kobj: &stats->kobj, ktype: &damon_sysfs_stats_ktype,
2119 parent: &scheme->kobj, fmt: "stats");
2120 if (err)
2121 kobject_put(kobj: &stats->kobj);
2122 else
2123 scheme->stats = stats;
2124 return err;
2125}
2126
2127static int damon_sysfs_scheme_set_tried_regions(
2128 struct damon_sysfs_scheme *scheme)
2129{
2130 struct damon_sysfs_scheme_regions *tried_regions =
2131 damon_sysfs_scheme_regions_alloc();
2132 int err;
2133
2134 if (!tried_regions)
2135 return -ENOMEM;
2136 err = kobject_init_and_add(kobj: &tried_regions->kobj,
2137 ktype: &damon_sysfs_scheme_regions_ktype, parent: &scheme->kobj,
2138 fmt: "tried_regions");
2139 if (err)
2140 kobject_put(kobj: &tried_regions->kobj);
2141 else
2142 scheme->tried_regions = tried_regions;
2143 return err;
2144}
2145
2146static int damon_sysfs_scheme_add_dirs(struct damon_sysfs_scheme *scheme)
2147{
2148 int err;
2149
2150 err = damon_sysfs_scheme_set_access_pattern(scheme);
2151 if (err)
2152 return err;
2153 err = damos_sysfs_set_dests(scheme);
2154 if (err)
2155 goto rmdir_put_access_pattern_out;
2156 err = damon_sysfs_scheme_set_quotas(scheme);
2157 if (err)
2158 goto put_dests_out;
2159 err = damon_sysfs_scheme_set_watermarks(scheme);
2160 if (err)
2161 goto rmdir_put_quotas_access_pattern_out;
2162 err = damos_sysfs_set_filter_dirs(scheme);
2163 if (err)
2164 goto put_watermarks_quotas_access_pattern_out;
2165 err = damon_sysfs_scheme_set_stats(scheme);
2166 if (err)
2167 goto put_filters_watermarks_quotas_access_pattern_out;
2168 err = damon_sysfs_scheme_set_tried_regions(scheme);
2169 if (err)
2170 goto put_tried_regions_out;
2171 return 0;
2172
2173put_tried_regions_out:
2174 kobject_put(kobj: &scheme->tried_regions->kobj);
2175 scheme->tried_regions = NULL;
2176put_filters_watermarks_quotas_access_pattern_out:
2177 kobject_put(kobj: &scheme->ops_filters->kobj);
2178 scheme->ops_filters = NULL;
2179 kobject_put(kobj: &scheme->core_filters->kobj);
2180 scheme->core_filters = NULL;
2181 kobject_put(kobj: &scheme->filters->kobj);
2182 scheme->filters = NULL;
2183put_watermarks_quotas_access_pattern_out:
2184 kobject_put(kobj: &scheme->watermarks->kobj);
2185 scheme->watermarks = NULL;
2186rmdir_put_quotas_access_pattern_out:
2187 damon_sysfs_quotas_rm_dirs(quotas: scheme->quotas);
2188 kobject_put(kobj: &scheme->quotas->kobj);
2189 scheme->quotas = NULL;
2190put_dests_out:
2191 kobject_put(kobj: &scheme->dests->kobj);
2192 scheme->dests = NULL;
2193rmdir_put_access_pattern_out:
2194 damon_sysfs_access_pattern_rm_dirs(access_pattern: scheme->access_pattern);
2195 kobject_put(kobj: &scheme->access_pattern->kobj);
2196 scheme->access_pattern = NULL;
2197 return err;
2198}
2199
2200static void damon_sysfs_scheme_rm_dirs(struct damon_sysfs_scheme *scheme)
2201{
2202 damon_sysfs_access_pattern_rm_dirs(access_pattern: scheme->access_pattern);
2203 kobject_put(kobj: &scheme->access_pattern->kobj);
2204 damos_sysfs_dests_rm_dirs(dests: scheme->dests);
2205 kobject_put(kobj: &scheme->dests->kobj);
2206 damon_sysfs_quotas_rm_dirs(quotas: scheme->quotas);
2207 kobject_put(kobj: &scheme->quotas->kobj);
2208 kobject_put(kobj: &scheme->watermarks->kobj);
2209 damon_sysfs_scheme_filters_rm_dirs(filters: scheme->filters);
2210 kobject_put(kobj: &scheme->filters->kobj);
2211 damon_sysfs_scheme_filters_rm_dirs(filters: scheme->core_filters);
2212 kobject_put(kobj: &scheme->core_filters->kobj);
2213 damon_sysfs_scheme_filters_rm_dirs(filters: scheme->ops_filters);
2214 kobject_put(kobj: &scheme->ops_filters->kobj);
2215 kobject_put(kobj: &scheme->stats->kobj);
2216 damon_sysfs_scheme_regions_rm_dirs(regions: scheme->tried_regions);
2217 kobject_put(kobj: &scheme->tried_regions->kobj);
2218}
2219
2220static ssize_t action_show(struct kobject *kobj, struct kobj_attribute *attr,
2221 char *buf)
2222{
2223 struct damon_sysfs_scheme *scheme = container_of(kobj,
2224 struct damon_sysfs_scheme, kobj);
2225 int i;
2226
2227 for (i = 0; i < ARRAY_SIZE(damos_sysfs_action_names); i++) {
2228 struct damos_sysfs_action_name *action_name;
2229
2230 action_name = &damos_sysfs_action_names[i];
2231 if (action_name->action == scheme->action)
2232 return sysfs_emit(buf, fmt: "%s\n", action_name->name);
2233 }
2234 return -EINVAL;
2235}
2236
2237static ssize_t action_store(struct kobject *kobj, struct kobj_attribute *attr,
2238 const char *buf, size_t count)
2239{
2240 struct damon_sysfs_scheme *scheme = container_of(kobj,
2241 struct damon_sysfs_scheme, kobj);
2242 int i;
2243
2244 for (i = 0; i < ARRAY_SIZE(damos_sysfs_action_names); i++) {
2245 struct damos_sysfs_action_name *action_name;
2246
2247 action_name = &damos_sysfs_action_names[i];
2248 if (sysfs_streq(s1: buf, s2: action_name->name)) {
2249 scheme->action = action_name->action;
2250 return count;
2251 }
2252 }
2253 return -EINVAL;
2254}
2255
2256static ssize_t apply_interval_us_show(struct kobject *kobj,
2257 struct kobj_attribute *attr, char *buf)
2258{
2259 struct damon_sysfs_scheme *scheme = container_of(kobj,
2260 struct damon_sysfs_scheme, kobj);
2261
2262 return sysfs_emit(buf, fmt: "%lu\n", scheme->apply_interval_us);
2263}
2264
2265static ssize_t apply_interval_us_store(struct kobject *kobj,
2266 struct kobj_attribute *attr, const char *buf, size_t count)
2267{
2268 struct damon_sysfs_scheme *scheme = container_of(kobj,
2269 struct damon_sysfs_scheme, kobj);
2270 int err = kstrtoul(s: buf, base: 0, res: &scheme->apply_interval_us);
2271
2272 return err ? err : count;
2273}
2274
2275static ssize_t target_nid_show(struct kobject *kobj,
2276 struct kobj_attribute *attr, char *buf)
2277{
2278 struct damon_sysfs_scheme *scheme = container_of(kobj,
2279 struct damon_sysfs_scheme, kobj);
2280
2281 return sysfs_emit(buf, fmt: "%d\n", scheme->target_nid);
2282}
2283
2284static ssize_t target_nid_store(struct kobject *kobj,
2285 struct kobj_attribute *attr, const char *buf, size_t count)
2286{
2287 struct damon_sysfs_scheme *scheme = container_of(kobj,
2288 struct damon_sysfs_scheme, kobj);
2289 int err = 0;
2290
2291 /* TODO: error handling for target_nid range. */
2292 err = kstrtoint(s: buf, base: 0, res: &scheme->target_nid);
2293
2294 return err ? err : count;
2295}
2296
2297static void damon_sysfs_scheme_release(struct kobject *kobj)
2298{
2299 kfree(container_of(kobj, struct damon_sysfs_scheme, kobj));
2300}
2301
2302static struct kobj_attribute damon_sysfs_scheme_action_attr =
2303 __ATTR_RW_MODE(action, 0600);
2304
2305static struct kobj_attribute damon_sysfs_scheme_apply_interval_us_attr =
2306 __ATTR_RW_MODE(apply_interval_us, 0600);
2307
2308static struct kobj_attribute damon_sysfs_scheme_target_nid_attr =
2309 __ATTR_RW_MODE(target_nid, 0600);
2310
2311static struct attribute *damon_sysfs_scheme_attrs[] = {
2312 &damon_sysfs_scheme_action_attr.attr,
2313 &damon_sysfs_scheme_apply_interval_us_attr.attr,
2314 &damon_sysfs_scheme_target_nid_attr.attr,
2315 NULL,
2316};
2317ATTRIBUTE_GROUPS(damon_sysfs_scheme);
2318
2319static const struct kobj_type damon_sysfs_scheme_ktype = {
2320 .release = damon_sysfs_scheme_release,
2321 .sysfs_ops = &kobj_sysfs_ops,
2322 .default_groups = damon_sysfs_scheme_groups,
2323};
2324
2325/*
2326 * schemes directory
2327 */
2328
2329struct damon_sysfs_schemes *damon_sysfs_schemes_alloc(void)
2330{
2331 return kzalloc(sizeof(struct damon_sysfs_schemes), GFP_KERNEL);
2332}
2333
2334void damon_sysfs_schemes_rm_dirs(struct damon_sysfs_schemes *schemes)
2335{
2336 struct damon_sysfs_scheme **schemes_arr = schemes->schemes_arr;
2337 int i;
2338
2339 for (i = 0; i < schemes->nr; i++) {
2340 damon_sysfs_scheme_rm_dirs(scheme: schemes_arr[i]);
2341 kobject_put(kobj: &schemes_arr[i]->kobj);
2342 }
2343 schemes->nr = 0;
2344 kfree(objp: schemes_arr);
2345 schemes->schemes_arr = NULL;
2346}
2347
2348static int damon_sysfs_schemes_add_dirs(struct damon_sysfs_schemes *schemes,
2349 int nr_schemes)
2350{
2351 struct damon_sysfs_scheme **schemes_arr, *scheme;
2352 int err, i;
2353
2354 damon_sysfs_schemes_rm_dirs(schemes);
2355 if (!nr_schemes)
2356 return 0;
2357
2358 schemes_arr = kmalloc_array(nr_schemes, sizeof(*schemes_arr),
2359 GFP_KERNEL | __GFP_NOWARN);
2360 if (!schemes_arr)
2361 return -ENOMEM;
2362 schemes->schemes_arr = schemes_arr;
2363
2364 for (i = 0; i < nr_schemes; i++) {
2365 /*
2366 * apply_interval_us as 0 means same to aggregation interval
2367 * (same to before-apply_interval behavior)
2368 */
2369 scheme = damon_sysfs_scheme_alloc(action: DAMOS_STAT, apply_interval_us: 0);
2370 if (!scheme) {
2371 damon_sysfs_schemes_rm_dirs(schemes);
2372 return -ENOMEM;
2373 }
2374
2375 err = kobject_init_and_add(kobj: &scheme->kobj,
2376 ktype: &damon_sysfs_scheme_ktype, parent: &schemes->kobj,
2377 fmt: "%d", i);
2378 if (err)
2379 goto out;
2380 err = damon_sysfs_scheme_add_dirs(scheme);
2381 if (err)
2382 goto out;
2383
2384 schemes_arr[i] = scheme;
2385 schemes->nr++;
2386 }
2387 return 0;
2388
2389out:
2390 damon_sysfs_schemes_rm_dirs(schemes);
2391 kobject_put(kobj: &scheme->kobj);
2392 return err;
2393}
2394
2395static ssize_t nr_schemes_show(struct kobject *kobj,
2396 struct kobj_attribute *attr, char *buf)
2397{
2398 struct damon_sysfs_schemes *schemes = container_of(kobj,
2399 struct damon_sysfs_schemes, kobj);
2400
2401 return sysfs_emit(buf, fmt: "%d\n", schemes->nr);
2402}
2403
2404static ssize_t nr_schemes_store(struct kobject *kobj,
2405 struct kobj_attribute *attr, const char *buf, size_t count)
2406{
2407 struct damon_sysfs_schemes *schemes;
2408 int nr, err = kstrtoint(s: buf, base: 0, res: &nr);
2409
2410 if (err)
2411 return err;
2412 if (nr < 0)
2413 return -EINVAL;
2414
2415 schemes = container_of(kobj, struct damon_sysfs_schemes, kobj);
2416
2417 if (!mutex_trylock(&damon_sysfs_lock))
2418 return -EBUSY;
2419 err = damon_sysfs_schemes_add_dirs(schemes, nr_schemes: nr);
2420 mutex_unlock(lock: &damon_sysfs_lock);
2421 if (err)
2422 return err;
2423 return count;
2424}
2425
2426static void damon_sysfs_schemes_release(struct kobject *kobj)
2427{
2428 kfree(container_of(kobj, struct damon_sysfs_schemes, kobj));
2429}
2430
2431static struct kobj_attribute damon_sysfs_schemes_nr_attr =
2432 __ATTR_RW_MODE(nr_schemes, 0600);
2433
2434static struct attribute *damon_sysfs_schemes_attrs[] = {
2435 &damon_sysfs_schemes_nr_attr.attr,
2436 NULL,
2437};
2438ATTRIBUTE_GROUPS(damon_sysfs_schemes);
2439
2440const struct kobj_type damon_sysfs_schemes_ktype = {
2441 .release = damon_sysfs_schemes_release,
2442 .sysfs_ops = &kobj_sysfs_ops,
2443 .default_groups = damon_sysfs_schemes_groups,
2444};
2445
2446static bool damon_sysfs_memcg_path_eq(struct mem_cgroup *memcg,
2447 char *memcg_path_buf, char *path)
2448{
2449#ifdef CONFIG_MEMCG
2450 cgroup_path(cgrp: memcg->css.cgroup, buf: memcg_path_buf, PATH_MAX);
2451 if (sysfs_streq(s1: memcg_path_buf, s2: path))
2452 return true;
2453#endif /* CONFIG_MEMCG */
2454 return false;
2455}
2456
2457static int damon_sysfs_memcg_path_to_id(char *memcg_path, unsigned short *id)
2458{
2459 struct mem_cgroup *memcg;
2460 char *path;
2461 bool found = false;
2462
2463 if (!memcg_path)
2464 return -EINVAL;
2465
2466 path = kmalloc_array(PATH_MAX, sizeof(*path), GFP_KERNEL);
2467 if (!path)
2468 return -ENOMEM;
2469
2470 for (memcg = mem_cgroup_iter(NULL, NULL, NULL); memcg;
2471 memcg = mem_cgroup_iter(NULL, memcg, NULL)) {
2472 /* skip removed memcg */
2473 if (!mem_cgroup_id(memcg))
2474 continue;
2475 if (damon_sysfs_memcg_path_eq(memcg, memcg_path_buf: path, path: memcg_path)) {
2476 *id = mem_cgroup_id(memcg);
2477 found = true;
2478 break;
2479 }
2480 }
2481
2482 kfree(objp: path);
2483 return found ? 0 : -EINVAL;
2484}
2485
2486static int damon_sysfs_add_scheme_filters(struct damos *scheme,
2487 struct damon_sysfs_scheme_filters *sysfs_filters)
2488{
2489 int i;
2490
2491 for (i = 0; i < sysfs_filters->nr; i++) {
2492 struct damon_sysfs_scheme_filter *sysfs_filter =
2493 sysfs_filters->filters_arr[i];
2494 struct damos_filter *filter =
2495 damos_new_filter(type: sysfs_filter->type,
2496 matching: sysfs_filter->matching,
2497 allow: sysfs_filter->allow);
2498 int err;
2499
2500 if (!filter)
2501 return -ENOMEM;
2502 if (filter->type == DAMOS_FILTER_TYPE_MEMCG) {
2503 err = damon_sysfs_memcg_path_to_id(
2504 memcg_path: sysfs_filter->memcg_path,
2505 id: &filter->memcg_id);
2506 if (err) {
2507 damos_destroy_filter(f: filter);
2508 return err;
2509 }
2510 } else if (filter->type == DAMOS_FILTER_TYPE_ADDR) {
2511 if (sysfs_filter->addr_range.end <
2512 sysfs_filter->addr_range.start) {
2513 damos_destroy_filter(f: filter);
2514 return -EINVAL;
2515 }
2516 filter->addr_range = sysfs_filter->addr_range;
2517 } else if (filter->type == DAMOS_FILTER_TYPE_TARGET) {
2518 filter->target_idx = sysfs_filter->target_idx;
2519 } else if (filter->type == DAMOS_FILTER_TYPE_HUGEPAGE_SIZE) {
2520 if (sysfs_filter->sz_range.min >
2521 sysfs_filter->sz_range.max) {
2522 damos_destroy_filter(f: filter);
2523 return -EINVAL;
2524 }
2525 filter->sz_range = sysfs_filter->sz_range;
2526 }
2527
2528 damos_add_filter(s: scheme, f: filter);
2529 }
2530 return 0;
2531}
2532
2533static int damos_sysfs_add_quota_score(
2534 struct damos_sysfs_quota_goals *sysfs_goals,
2535 struct damos_quota *quota)
2536{
2537 struct damos_quota_goal *goal;
2538 int i, err;
2539
2540 for (i = 0; i < sysfs_goals->nr; i++) {
2541 struct damos_sysfs_quota_goal *sysfs_goal =
2542 sysfs_goals->goals_arr[i];
2543
2544 if (!sysfs_goal->target_value)
2545 continue;
2546
2547 goal = damos_new_quota_goal(metric: sysfs_goal->metric,
2548 target_value: sysfs_goal->target_value);
2549 if (!goal)
2550 return -ENOMEM;
2551 switch (sysfs_goal->metric) {
2552 case DAMOS_QUOTA_USER_INPUT:
2553 goal->current_value = sysfs_goal->current_value;
2554 break;
2555 case DAMOS_QUOTA_NODE_MEM_USED_BP:
2556 case DAMOS_QUOTA_NODE_MEM_FREE_BP:
2557 goal->nid = sysfs_goal->nid;
2558 break;
2559 case DAMOS_QUOTA_NODE_MEMCG_USED_BP:
2560 case DAMOS_QUOTA_NODE_MEMCG_FREE_BP:
2561 err = damon_sysfs_memcg_path_to_id(
2562 memcg_path: sysfs_goal->path, id: &goal->memcg_id);
2563 if (err) {
2564 damos_destroy_quota_goal(goal);
2565 return err;
2566 }
2567 goal->nid = sysfs_goal->nid;
2568 break;
2569 default:
2570 break;
2571 }
2572 damos_add_quota_goal(q: quota, g: goal);
2573 }
2574 return 0;
2575}
2576
2577int damos_sysfs_set_quota_scores(struct damon_sysfs_schemes *sysfs_schemes,
2578 struct damon_ctx *ctx)
2579{
2580 struct damos *scheme;
2581 struct damos_quota quota = {};
2582 int i = 0;
2583
2584 INIT_LIST_HEAD(list: &quota.goals);
2585 damon_for_each_scheme(scheme, ctx) {
2586 struct damon_sysfs_scheme *sysfs_scheme;
2587 struct damos_quota_goal *g, *g_next;
2588 int err;
2589
2590 /* user could have removed the scheme sysfs dir */
2591 if (i >= sysfs_schemes->nr)
2592 break;
2593
2594 sysfs_scheme = sysfs_schemes->schemes_arr[i];
2595 err = damos_sysfs_add_quota_score(sysfs_goals: sysfs_scheme->quotas->goals,
2596 quota: &quota);
2597 if (err) {
2598 damos_for_each_quota_goal_safe(g, g_next, &quota)
2599 damos_destroy_quota_goal(goal: g);
2600 return err;
2601 }
2602 err = damos_commit_quota_goals(dst: &scheme->quota, src: &quota);
2603 damos_for_each_quota_goal_safe(g, g_next, &quota)
2604 damos_destroy_quota_goal(goal: g);
2605 if (err)
2606 return err;
2607 i++;
2608 }
2609 return 0;
2610}
2611
2612void damos_sysfs_update_effective_quotas(
2613 struct damon_sysfs_schemes *sysfs_schemes,
2614 struct damon_ctx *ctx)
2615{
2616 struct damos *scheme;
2617 int schemes_idx = 0;
2618
2619 damon_for_each_scheme(scheme, ctx) {
2620 struct damon_sysfs_quotas *sysfs_quotas;
2621
2622 /* user could have removed the scheme sysfs dir */
2623 if (schemes_idx >= sysfs_schemes->nr)
2624 break;
2625
2626 sysfs_quotas =
2627 sysfs_schemes->schemes_arr[schemes_idx++]->quotas;
2628 sysfs_quotas->effective_sz = scheme->quota.esz;
2629 }
2630}
2631
2632static int damos_sysfs_add_migrate_dest(struct damos *scheme,
2633 struct damos_sysfs_dests *sysfs_dests)
2634{
2635 struct damos_migrate_dests *dests = &scheme->migrate_dests;
2636 int i;
2637
2638 dests->node_id_arr = kmalloc_array(sysfs_dests->nr,
2639 sizeof(*dests->node_id_arr), GFP_KERNEL);
2640 if (!dests->node_id_arr)
2641 return -ENOMEM;
2642 dests->weight_arr = kmalloc_array(sysfs_dests->nr,
2643 sizeof(*dests->weight_arr), GFP_KERNEL);
2644 if (!dests->weight_arr)
2645 /* ->node_id_arr will be freed by scheme destruction */
2646 return -ENOMEM;
2647 for (i = 0; i < sysfs_dests->nr; i++) {
2648 dests->node_id_arr[i] = sysfs_dests->dests_arr[i]->id;
2649 dests->weight_arr[i] = sysfs_dests->dests_arr[i]->weight;
2650 }
2651 dests->nr_dests = sysfs_dests->nr;
2652 return 0;
2653}
2654
2655static struct damos *damon_sysfs_mk_scheme(
2656 struct damon_sysfs_scheme *sysfs_scheme)
2657{
2658 struct damon_sysfs_access_pattern *access_pattern =
2659 sysfs_scheme->access_pattern;
2660 struct damon_sysfs_quotas *sysfs_quotas = sysfs_scheme->quotas;
2661 struct damon_sysfs_weights *sysfs_weights = sysfs_quotas->weights;
2662 struct damon_sysfs_watermarks *sysfs_wmarks = sysfs_scheme->watermarks;
2663 struct damos *scheme;
2664 int err;
2665
2666 struct damos_access_pattern pattern = {
2667 .min_sz_region = access_pattern->sz->min,
2668 .max_sz_region = access_pattern->sz->max,
2669 .min_nr_accesses = access_pattern->nr_accesses->min,
2670 .max_nr_accesses = access_pattern->nr_accesses->max,
2671 .min_age_region = access_pattern->age->min,
2672 .max_age_region = access_pattern->age->max,
2673 };
2674 struct damos_quota quota = {
2675 .ms = sysfs_quotas->ms,
2676 .sz = sysfs_quotas->sz,
2677 .reset_interval = sysfs_quotas->reset_interval_ms,
2678 .weight_sz = sysfs_weights->sz,
2679 .weight_nr_accesses = sysfs_weights->nr_accesses,
2680 .weight_age = sysfs_weights->age,
2681 };
2682 struct damos_watermarks wmarks = {
2683 .metric = sysfs_wmarks->metric,
2684 .interval = sysfs_wmarks->interval_us,
2685 .high = sysfs_wmarks->high,
2686 .mid = sysfs_wmarks->mid,
2687 .low = sysfs_wmarks->low,
2688 };
2689
2690 scheme = damon_new_scheme(pattern: &pattern, action: sysfs_scheme->action,
2691 apply_interval_us: sysfs_scheme->apply_interval_us, quota: &quota, wmarks: &wmarks,
2692 target_nid: sysfs_scheme->target_nid);
2693 if (!scheme)
2694 return NULL;
2695
2696 err = damos_sysfs_add_quota_score(sysfs_goals: sysfs_quotas->goals, quota: &scheme->quota);
2697 if (err) {
2698 damon_destroy_scheme(s: scheme);
2699 return NULL;
2700 }
2701
2702 err = damon_sysfs_add_scheme_filters(scheme, sysfs_filters: sysfs_scheme->core_filters);
2703 if (err) {
2704 damon_destroy_scheme(s: scheme);
2705 return NULL;
2706 }
2707 err = damon_sysfs_add_scheme_filters(scheme, sysfs_filters: sysfs_scheme->ops_filters);
2708 if (err) {
2709 damon_destroy_scheme(s: scheme);
2710 return NULL;
2711 }
2712 err = damon_sysfs_add_scheme_filters(scheme, sysfs_filters: sysfs_scheme->filters);
2713 if (err) {
2714 damon_destroy_scheme(s: scheme);
2715 return NULL;
2716 }
2717 err = damos_sysfs_add_migrate_dest(scheme, sysfs_dests: sysfs_scheme->dests);
2718 if (err) {
2719 damon_destroy_scheme(s: scheme);
2720 return NULL;
2721 }
2722 return scheme;
2723}
2724
2725int damon_sysfs_add_schemes(struct damon_ctx *ctx,
2726 struct damon_sysfs_schemes *sysfs_schemes)
2727{
2728 int i;
2729
2730 for (i = 0; i < sysfs_schemes->nr; i++) {
2731 struct damos *scheme, *next;
2732
2733 scheme = damon_sysfs_mk_scheme(sysfs_scheme: sysfs_schemes->schemes_arr[i]);
2734 if (!scheme) {
2735 damon_for_each_scheme_safe(scheme, next, ctx)
2736 damon_destroy_scheme(s: scheme);
2737 return -ENOMEM;
2738 }
2739 damon_add_scheme(ctx, s: scheme);
2740 }
2741 return 0;
2742}
2743
2744void damon_sysfs_schemes_update_stats(
2745 struct damon_sysfs_schemes *sysfs_schemes,
2746 struct damon_ctx *ctx)
2747{
2748 struct damos *scheme;
2749 int schemes_idx = 0;
2750
2751 damon_for_each_scheme(scheme, ctx) {
2752 struct damon_sysfs_stats *sysfs_stats;
2753
2754 /* user could have removed the scheme sysfs dir */
2755 if (schemes_idx >= sysfs_schemes->nr)
2756 break;
2757
2758 sysfs_stats = sysfs_schemes->schemes_arr[schemes_idx++]->stats;
2759 sysfs_stats->nr_tried = scheme->stat.nr_tried;
2760 sysfs_stats->sz_tried = scheme->stat.sz_tried;
2761 sysfs_stats->nr_applied = scheme->stat.nr_applied;
2762 sysfs_stats->sz_applied = scheme->stat.sz_applied;
2763 sysfs_stats->sz_ops_filter_passed =
2764 scheme->stat.sz_ops_filter_passed;
2765 sysfs_stats->qt_exceeds = scheme->stat.qt_exceeds;
2766 }
2767}
2768
2769/**
2770 * damos_sysfs_populate_region_dir() - Populate a schemes tried region dir.
2771 * @sysfs_schemes: Schemes directory to populate regions directory.
2772 * @ctx: Corresponding DAMON context.
2773 * @t: DAMON target of @r.
2774 * @r: DAMON region to populate the directory for.
2775 * @s: Corresponding scheme.
2776 * @total_bytes_only: Whether the request is for bytes update only.
2777 * @sz_filter_passed: Bytes of @r that passed filters of @s.
2778 *
2779 * Called from DAMOS walk callback while holding damon_sysfs_lock.
2780 */
2781void damos_sysfs_populate_region_dir(struct damon_sysfs_schemes *sysfs_schemes,
2782 struct damon_ctx *ctx, struct damon_target *t,
2783 struct damon_region *r, struct damos *s, bool total_bytes_only,
2784 unsigned long sz_filter_passed)
2785{
2786 struct damos *scheme;
2787 struct damon_sysfs_scheme_regions *sysfs_regions;
2788 struct damon_sysfs_scheme_region *region;
2789 int schemes_idx = 0;
2790
2791 damon_for_each_scheme(scheme, ctx) {
2792 if (scheme == s)
2793 break;
2794 schemes_idx++;
2795 }
2796
2797 /* user could have removed the scheme sysfs dir */
2798 if (schemes_idx >= sysfs_schemes->nr)
2799 return;
2800
2801 sysfs_regions = sysfs_schemes->schemes_arr[schemes_idx]->tried_regions;
2802 sysfs_regions->total_bytes += r->ar.end - r->ar.start;
2803 if (total_bytes_only)
2804 return;
2805
2806 region = damon_sysfs_scheme_region_alloc(region: r);
2807 if (!region)
2808 return;
2809 region->sz_filter_passed = sz_filter_passed;
2810 list_add_tail(new: &region->list, head: &sysfs_regions->regions_list);
2811 sysfs_regions->nr_regions++;
2812 if (kobject_init_and_add(kobj: &region->kobj,
2813 ktype: &damon_sysfs_scheme_region_ktype,
2814 parent: &sysfs_regions->kobj, fmt: "%d",
2815 sysfs_regions->nr_regions++)) {
2816 kobject_put(kobj: &region->kobj);
2817 }
2818}
2819
2820int damon_sysfs_schemes_clear_regions(
2821 struct damon_sysfs_schemes *sysfs_schemes)
2822{
2823 int i;
2824
2825 for (i = 0; i < sysfs_schemes->nr; i++) {
2826 struct damon_sysfs_scheme *sysfs_scheme;
2827
2828 sysfs_scheme = sysfs_schemes->schemes_arr[i];
2829 damon_sysfs_scheme_regions_rm_dirs(
2830 regions: sysfs_scheme->tried_regions);
2831 sysfs_scheme->tried_regions->total_bytes = 0;
2832 }
2833 return 0;
2834}
2835

source code of linux/mm/damon/sysfs-schemes.c