Loading...
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 struct list_head list;
23};
24
25static struct damon_sysfs_scheme_region *damon_sysfs_scheme_region_alloc(
26 struct damon_region *region)
27{
28 struct damon_sysfs_scheme_region *sysfs_region = kmalloc(
29 sizeof(*sysfs_region), GFP_KERNEL);
30
31 if (!sysfs_region)
32 return NULL;
33 sysfs_region->kobj = (struct kobject){};
34 sysfs_region->ar = region->ar;
35 sysfs_region->nr_accesses = region->nr_accesses_bp / 10000;
36 sysfs_region->age = region->age;
37 INIT_LIST_HEAD(&sysfs_region->list);
38 return sysfs_region;
39}
40
41static ssize_t start_show(struct kobject *kobj, struct kobj_attribute *attr,
42 char *buf)
43{
44 struct damon_sysfs_scheme_region *region = container_of(kobj,
45 struct damon_sysfs_scheme_region, kobj);
46
47 return sysfs_emit(buf, "%lu\n", region->ar.start);
48}
49
50static ssize_t end_show(struct kobject *kobj, struct kobj_attribute *attr,
51 char *buf)
52{
53 struct damon_sysfs_scheme_region *region = container_of(kobj,
54 struct damon_sysfs_scheme_region, kobj);
55
56 return sysfs_emit(buf, "%lu\n", region->ar.end);
57}
58
59static ssize_t nr_accesses_show(struct kobject *kobj,
60 struct kobj_attribute *attr, char *buf)
61{
62 struct damon_sysfs_scheme_region *region = container_of(kobj,
63 struct damon_sysfs_scheme_region, kobj);
64
65 return sysfs_emit(buf, "%u\n", region->nr_accesses);
66}
67
68static ssize_t age_show(struct kobject *kobj, struct kobj_attribute *attr,
69 char *buf)
70{
71 struct damon_sysfs_scheme_region *region = container_of(kobj,
72 struct damon_sysfs_scheme_region, kobj);
73
74 return sysfs_emit(buf, "%u\n", region->age);
75}
76
77static void damon_sysfs_scheme_region_release(struct kobject *kobj)
78{
79 struct damon_sysfs_scheme_region *region = container_of(kobj,
80 struct damon_sysfs_scheme_region, kobj);
81
82 list_del(®ion->list);
83 kfree(region);
84}
85
86static struct kobj_attribute damon_sysfs_scheme_region_start_attr =
87 __ATTR_RO_MODE(start, 0400);
88
89static struct kobj_attribute damon_sysfs_scheme_region_end_attr =
90 __ATTR_RO_MODE(end, 0400);
91
92static struct kobj_attribute damon_sysfs_scheme_region_nr_accesses_attr =
93 __ATTR_RO_MODE(nr_accesses, 0400);
94
95static struct kobj_attribute damon_sysfs_scheme_region_age_attr =
96 __ATTR_RO_MODE(age, 0400);
97
98static struct attribute *damon_sysfs_scheme_region_attrs[] = {
99 &damon_sysfs_scheme_region_start_attr.attr,
100 &damon_sysfs_scheme_region_end_attr.attr,
101 &damon_sysfs_scheme_region_nr_accesses_attr.attr,
102 &damon_sysfs_scheme_region_age_attr.attr,
103 NULL,
104};
105ATTRIBUTE_GROUPS(damon_sysfs_scheme_region);
106
107static const struct kobj_type damon_sysfs_scheme_region_ktype = {
108 .release = damon_sysfs_scheme_region_release,
109 .sysfs_ops = &kobj_sysfs_ops,
110 .default_groups = damon_sysfs_scheme_region_groups,
111};
112
113/*
114 * scheme regions directory
115 */
116
117/*
118 * enum damos_sysfs_regions_upd_status - Represent DAMOS tried regions update
119 * status
120 * @DAMOS_TRIED_REGIONS_UPD_IDLE: Waiting for next request.
121 * @DAMOS_TRIED_REGIONS_UPD_STARTED: Update started.
122 * @DAMOS_TRIED_REGIONS_UPD_FINISHED: Update finished.
123 *
124 * Each DAMON-based operation scheme (&struct damos) has its own apply
125 * interval, and we need to expose the scheme tried regions based on only
126 * single snapshot. For this, we keep the tried regions update status for each
127 * scheme. The status becomes 'idle' at the beginning.
128 *
129 * Once the tried regions update request is received, the request handling
130 * start function (damon_sysfs_scheme_update_regions_start()) sets the status
131 * of all schemes as 'idle' again, and register ->before_damos_apply()
132 * callback.
133 *
134 * Then, the first followup ->before_damos_apply() callback
135 * (damon_sysfs_before_damos_apply()) sets the status 'started'. The first
136 * ->after_sampling() or ->after_aggregation() callback
137 * (damon_sysfs_cmd_request_callback()) after the call is called only after
138 * the scheme is completely applied to the given snapshot. Hence the callback
139 * knows the situation by showing 'started' status, and sets the status as
140 * 'finished'. Then, damon_sysfs_before_damos_apply() understands the
141 * situation by showing the 'finished' status and do nothing.
142 *
143 * If DAMOS is not applied to any region due to any reasons including the
144 * access pattern, the watermarks, the quotas, and the filters,
145 * ->before_damos_apply() will not be called back. Until the situation is
146 * changed, the update will not be finished. To avoid this,
147 * damon_sysfs_after_sampling() set the status as 'finished' if more than two
148 * apply intervals of the scheme is passed while the state is 'idle'.
149 *
150 * Finally, the tried regions request handling finisher function
151 * (damon_sysfs_schemes_update_regions_stop()) unregisters the callbacks.
152 */
153enum damos_sysfs_regions_upd_status {
154 DAMOS_TRIED_REGIONS_UPD_IDLE,
155 DAMOS_TRIED_REGIONS_UPD_STARTED,
156 DAMOS_TRIED_REGIONS_UPD_FINISHED,
157};
158
159struct damon_sysfs_scheme_regions {
160 struct kobject kobj;
161 struct list_head regions_list;
162 int nr_regions;
163 unsigned long total_bytes;
164 enum damos_sysfs_regions_upd_status upd_status;
165 unsigned long upd_timeout_jiffies;
166};
167
168static struct damon_sysfs_scheme_regions *
169damon_sysfs_scheme_regions_alloc(void)
170{
171 struct damon_sysfs_scheme_regions *regions = kmalloc(sizeof(*regions),
172 GFP_KERNEL);
173
174 if (!regions)
175 return NULL;
176
177 regions->kobj = (struct kobject){};
178 INIT_LIST_HEAD(®ions->regions_list);
179 regions->nr_regions = 0;
180 regions->total_bytes = 0;
181 regions->upd_status = DAMOS_TRIED_REGIONS_UPD_IDLE;
182 return regions;
183}
184
185static ssize_t total_bytes_show(struct kobject *kobj,
186 struct kobj_attribute *attr, char *buf)
187{
188 struct damon_sysfs_scheme_regions *regions = container_of(kobj,
189 struct damon_sysfs_scheme_regions, kobj);
190
191 return sysfs_emit(buf, "%lu\n", regions->total_bytes);
192}
193
194static void damon_sysfs_scheme_regions_rm_dirs(
195 struct damon_sysfs_scheme_regions *regions)
196{
197 struct damon_sysfs_scheme_region *r, *next;
198
199 list_for_each_entry_safe(r, next, ®ions->regions_list, list) {
200 /* release function deletes it from the list */
201 kobject_put(&r->kobj);
202 regions->nr_regions--;
203 }
204}
205
206static void damon_sysfs_scheme_regions_release(struct kobject *kobj)
207{
208 kfree(container_of(kobj, struct damon_sysfs_scheme_regions, kobj));
209}
210
211static struct kobj_attribute damon_sysfs_scheme_regions_total_bytes_attr =
212 __ATTR_RO_MODE(total_bytes, 0400);
213
214static struct attribute *damon_sysfs_scheme_regions_attrs[] = {
215 &damon_sysfs_scheme_regions_total_bytes_attr.attr,
216 NULL,
217};
218ATTRIBUTE_GROUPS(damon_sysfs_scheme_regions);
219
220static const struct kobj_type damon_sysfs_scheme_regions_ktype = {
221 .release = damon_sysfs_scheme_regions_release,
222 .sysfs_ops = &kobj_sysfs_ops,
223 .default_groups = damon_sysfs_scheme_regions_groups,
224};
225
226/*
227 * schemes/stats directory
228 */
229
230struct damon_sysfs_stats {
231 struct kobject kobj;
232 unsigned long nr_tried;
233 unsigned long sz_tried;
234 unsigned long nr_applied;
235 unsigned long sz_applied;
236 unsigned long qt_exceeds;
237};
238
239static struct damon_sysfs_stats *damon_sysfs_stats_alloc(void)
240{
241 return kzalloc(sizeof(struct damon_sysfs_stats), GFP_KERNEL);
242}
243
244static ssize_t nr_tried_show(struct kobject *kobj, struct kobj_attribute *attr,
245 char *buf)
246{
247 struct damon_sysfs_stats *stats = container_of(kobj,
248 struct damon_sysfs_stats, kobj);
249
250 return sysfs_emit(buf, "%lu\n", stats->nr_tried);
251}
252
253static ssize_t sz_tried_show(struct kobject *kobj, struct kobj_attribute *attr,
254 char *buf)
255{
256 struct damon_sysfs_stats *stats = container_of(kobj,
257 struct damon_sysfs_stats, kobj);
258
259 return sysfs_emit(buf, "%lu\n", stats->sz_tried);
260}
261
262static ssize_t nr_applied_show(struct kobject *kobj,
263 struct kobj_attribute *attr, char *buf)
264{
265 struct damon_sysfs_stats *stats = container_of(kobj,
266 struct damon_sysfs_stats, kobj);
267
268 return sysfs_emit(buf, "%lu\n", stats->nr_applied);
269}
270
271static ssize_t sz_applied_show(struct kobject *kobj,
272 struct kobj_attribute *attr, char *buf)
273{
274 struct damon_sysfs_stats *stats = container_of(kobj,
275 struct damon_sysfs_stats, kobj);
276
277 return sysfs_emit(buf, "%lu\n", stats->sz_applied);
278}
279
280static ssize_t qt_exceeds_show(struct kobject *kobj,
281 struct kobj_attribute *attr, char *buf)
282{
283 struct damon_sysfs_stats *stats = container_of(kobj,
284 struct damon_sysfs_stats, kobj);
285
286 return sysfs_emit(buf, "%lu\n", stats->qt_exceeds);
287}
288
289static void damon_sysfs_stats_release(struct kobject *kobj)
290{
291 kfree(container_of(kobj, struct damon_sysfs_stats, kobj));
292}
293
294static struct kobj_attribute damon_sysfs_stats_nr_tried_attr =
295 __ATTR_RO_MODE(nr_tried, 0400);
296
297static struct kobj_attribute damon_sysfs_stats_sz_tried_attr =
298 __ATTR_RO_MODE(sz_tried, 0400);
299
300static struct kobj_attribute damon_sysfs_stats_nr_applied_attr =
301 __ATTR_RO_MODE(nr_applied, 0400);
302
303static struct kobj_attribute damon_sysfs_stats_sz_applied_attr =
304 __ATTR_RO_MODE(sz_applied, 0400);
305
306static struct kobj_attribute damon_sysfs_stats_qt_exceeds_attr =
307 __ATTR_RO_MODE(qt_exceeds, 0400);
308
309static struct attribute *damon_sysfs_stats_attrs[] = {
310 &damon_sysfs_stats_nr_tried_attr.attr,
311 &damon_sysfs_stats_sz_tried_attr.attr,
312 &damon_sysfs_stats_nr_applied_attr.attr,
313 &damon_sysfs_stats_sz_applied_attr.attr,
314 &damon_sysfs_stats_qt_exceeds_attr.attr,
315 NULL,
316};
317ATTRIBUTE_GROUPS(damon_sysfs_stats);
318
319static const struct kobj_type damon_sysfs_stats_ktype = {
320 .release = damon_sysfs_stats_release,
321 .sysfs_ops = &kobj_sysfs_ops,
322 .default_groups = damon_sysfs_stats_groups,
323};
324
325/*
326 * filter directory
327 */
328
329struct damon_sysfs_scheme_filter {
330 struct kobject kobj;
331 enum damos_filter_type type;
332 bool matching;
333 char *memcg_path;
334 struct damon_addr_range addr_range;
335 int target_idx;
336};
337
338static struct damon_sysfs_scheme_filter *damon_sysfs_scheme_filter_alloc(void)
339{
340 return kzalloc(sizeof(struct damon_sysfs_scheme_filter), GFP_KERNEL);
341}
342
343/* Should match with enum damos_filter_type */
344static const char * const damon_sysfs_scheme_filter_type_strs[] = {
345 "anon",
346 "memcg",
347 "young",
348 "addr",
349 "target",
350};
351
352static ssize_t type_show(struct kobject *kobj,
353 struct kobj_attribute *attr, char *buf)
354{
355 struct damon_sysfs_scheme_filter *filter = container_of(kobj,
356 struct damon_sysfs_scheme_filter, kobj);
357
358 return sysfs_emit(buf, "%s\n",
359 damon_sysfs_scheme_filter_type_strs[filter->type]);
360}
361
362static ssize_t type_store(struct kobject *kobj,
363 struct kobj_attribute *attr, const char *buf, size_t count)
364{
365 struct damon_sysfs_scheme_filter *filter = container_of(kobj,
366 struct damon_sysfs_scheme_filter, kobj);
367 enum damos_filter_type type;
368 ssize_t ret = -EINVAL;
369
370 for (type = 0; type < NR_DAMOS_FILTER_TYPES; type++) {
371 if (sysfs_streq(buf, damon_sysfs_scheme_filter_type_strs[
372 type])) {
373 filter->type = type;
374 ret = count;
375 break;
376 }
377 }
378 return ret;
379}
380
381static ssize_t matching_show(struct kobject *kobj,
382 struct kobj_attribute *attr, char *buf)
383{
384 struct damon_sysfs_scheme_filter *filter = container_of(kobj,
385 struct damon_sysfs_scheme_filter, kobj);
386
387 return sysfs_emit(buf, "%c\n", filter->matching ? 'Y' : 'N');
388}
389
390static ssize_t matching_store(struct kobject *kobj,
391 struct kobj_attribute *attr, const char *buf, size_t count)
392{
393 struct damon_sysfs_scheme_filter *filter = container_of(kobj,
394 struct damon_sysfs_scheme_filter, kobj);
395 bool matching;
396 int err = kstrtobool(buf, &matching);
397
398 if (err)
399 return err;
400
401 filter->matching = matching;
402 return count;
403}
404
405static ssize_t memcg_path_show(struct kobject *kobj,
406 struct kobj_attribute *attr, char *buf)
407{
408 struct damon_sysfs_scheme_filter *filter = container_of(kobj,
409 struct damon_sysfs_scheme_filter, kobj);
410
411 return sysfs_emit(buf, "%s\n",
412 filter->memcg_path ? filter->memcg_path : "");
413}
414
415static ssize_t memcg_path_store(struct kobject *kobj,
416 struct kobj_attribute *attr, const char *buf, size_t count)
417{
418 struct damon_sysfs_scheme_filter *filter = container_of(kobj,
419 struct damon_sysfs_scheme_filter, kobj);
420 char *path = kmalloc(sizeof(*path) * (count + 1), GFP_KERNEL);
421
422 if (!path)
423 return -ENOMEM;
424
425 strscpy(path, buf, count + 1);
426 filter->memcg_path = path;
427 return count;
428}
429
430static ssize_t addr_start_show(struct kobject *kobj,
431 struct kobj_attribute *attr, char *buf)
432{
433 struct damon_sysfs_scheme_filter *filter = container_of(kobj,
434 struct damon_sysfs_scheme_filter, kobj);
435
436 return sysfs_emit(buf, "%lu\n", filter->addr_range.start);
437}
438
439static ssize_t addr_start_store(struct kobject *kobj,
440 struct kobj_attribute *attr, const char *buf, size_t count)
441{
442 struct damon_sysfs_scheme_filter *filter = container_of(kobj,
443 struct damon_sysfs_scheme_filter, kobj);
444 int err = kstrtoul(buf, 0, &filter->addr_range.start);
445
446 return err ? err : count;
447}
448
449static ssize_t addr_end_show(struct kobject *kobj,
450 struct kobj_attribute *attr, char *buf)
451{
452 struct damon_sysfs_scheme_filter *filter = container_of(kobj,
453 struct damon_sysfs_scheme_filter, kobj);
454
455 return sysfs_emit(buf, "%lu\n", filter->addr_range.end);
456}
457
458static ssize_t addr_end_store(struct kobject *kobj,
459 struct kobj_attribute *attr, const char *buf, size_t count)
460{
461 struct damon_sysfs_scheme_filter *filter = container_of(kobj,
462 struct damon_sysfs_scheme_filter, kobj);
463 int err = kstrtoul(buf, 0, &filter->addr_range.end);
464
465 return err ? err : count;
466}
467
468static ssize_t damon_target_idx_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, "%d\n", filter->target_idx);
475}
476
477static ssize_t damon_target_idx_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 int err = kstrtoint(buf, 0, &filter->target_idx);
483
484 return err ? err : count;
485}
486
487static void damon_sysfs_scheme_filter_release(struct kobject *kobj)
488{
489 struct damon_sysfs_scheme_filter *filter = container_of(kobj,
490 struct damon_sysfs_scheme_filter, kobj);
491
492 kfree(filter->memcg_path);
493 kfree(filter);
494}
495
496static struct kobj_attribute damon_sysfs_scheme_filter_type_attr =
497 __ATTR_RW_MODE(type, 0600);
498
499static struct kobj_attribute damon_sysfs_scheme_filter_matching_attr =
500 __ATTR_RW_MODE(matching, 0600);
501
502static struct kobj_attribute damon_sysfs_scheme_filter_memcg_path_attr =
503 __ATTR_RW_MODE(memcg_path, 0600);
504
505static struct kobj_attribute damon_sysfs_scheme_filter_addr_start_attr =
506 __ATTR_RW_MODE(addr_start, 0600);
507
508static struct kobj_attribute damon_sysfs_scheme_filter_addr_end_attr =
509 __ATTR_RW_MODE(addr_end, 0600);
510
511static struct kobj_attribute damon_sysfs_scheme_filter_damon_target_idx_attr =
512 __ATTR_RW_MODE(damon_target_idx, 0600);
513
514static struct attribute *damon_sysfs_scheme_filter_attrs[] = {
515 &damon_sysfs_scheme_filter_type_attr.attr,
516 &damon_sysfs_scheme_filter_matching_attr.attr,
517 &damon_sysfs_scheme_filter_memcg_path_attr.attr,
518 &damon_sysfs_scheme_filter_addr_start_attr.attr,
519 &damon_sysfs_scheme_filter_addr_end_attr.attr,
520 &damon_sysfs_scheme_filter_damon_target_idx_attr.attr,
521 NULL,
522};
523ATTRIBUTE_GROUPS(damon_sysfs_scheme_filter);
524
525static const struct kobj_type damon_sysfs_scheme_filter_ktype = {
526 .release = damon_sysfs_scheme_filter_release,
527 .sysfs_ops = &kobj_sysfs_ops,
528 .default_groups = damon_sysfs_scheme_filter_groups,
529};
530
531/*
532 * filters directory
533 */
534
535struct damon_sysfs_scheme_filters {
536 struct kobject kobj;
537 struct damon_sysfs_scheme_filter **filters_arr;
538 int nr;
539};
540
541static struct damon_sysfs_scheme_filters *
542damon_sysfs_scheme_filters_alloc(void)
543{
544 return kzalloc(sizeof(struct damon_sysfs_scheme_filters), GFP_KERNEL);
545}
546
547static void damon_sysfs_scheme_filters_rm_dirs(
548 struct damon_sysfs_scheme_filters *filters)
549{
550 struct damon_sysfs_scheme_filter **filters_arr = filters->filters_arr;
551 int i;
552
553 for (i = 0; i < filters->nr; i++)
554 kobject_put(&filters_arr[i]->kobj);
555 filters->nr = 0;
556 kfree(filters_arr);
557 filters->filters_arr = NULL;
558}
559
560static int damon_sysfs_scheme_filters_add_dirs(
561 struct damon_sysfs_scheme_filters *filters, int nr_filters)
562{
563 struct damon_sysfs_scheme_filter **filters_arr, *filter;
564 int err, i;
565
566 damon_sysfs_scheme_filters_rm_dirs(filters);
567 if (!nr_filters)
568 return 0;
569
570 filters_arr = kmalloc_array(nr_filters, sizeof(*filters_arr),
571 GFP_KERNEL | __GFP_NOWARN);
572 if (!filters_arr)
573 return -ENOMEM;
574 filters->filters_arr = filters_arr;
575
576 for (i = 0; i < nr_filters; i++) {
577 filter = damon_sysfs_scheme_filter_alloc();
578 if (!filter) {
579 damon_sysfs_scheme_filters_rm_dirs(filters);
580 return -ENOMEM;
581 }
582
583 err = kobject_init_and_add(&filter->kobj,
584 &damon_sysfs_scheme_filter_ktype,
585 &filters->kobj, "%d", i);
586 if (err) {
587 kobject_put(&filter->kobj);
588 damon_sysfs_scheme_filters_rm_dirs(filters);
589 return err;
590 }
591
592 filters_arr[i] = filter;
593 filters->nr++;
594 }
595 return 0;
596}
597
598static ssize_t nr_filters_show(struct kobject *kobj,
599 struct kobj_attribute *attr, char *buf)
600{
601 struct damon_sysfs_scheme_filters *filters = container_of(kobj,
602 struct damon_sysfs_scheme_filters, kobj);
603
604 return sysfs_emit(buf, "%d\n", filters->nr);
605}
606
607static ssize_t nr_filters_store(struct kobject *kobj,
608 struct kobj_attribute *attr, const char *buf, size_t count)
609{
610 struct damon_sysfs_scheme_filters *filters;
611 int nr, err = kstrtoint(buf, 0, &nr);
612
613 if (err)
614 return err;
615 if (nr < 0)
616 return -EINVAL;
617
618 filters = container_of(kobj, struct damon_sysfs_scheme_filters, kobj);
619
620 if (!mutex_trylock(&damon_sysfs_lock))
621 return -EBUSY;
622 err = damon_sysfs_scheme_filters_add_dirs(filters, nr);
623 mutex_unlock(&damon_sysfs_lock);
624 if (err)
625 return err;
626
627 return count;
628}
629
630static void damon_sysfs_scheme_filters_release(struct kobject *kobj)
631{
632 kfree(container_of(kobj, struct damon_sysfs_scheme_filters, kobj));
633}
634
635static struct kobj_attribute damon_sysfs_scheme_filters_nr_attr =
636 __ATTR_RW_MODE(nr_filters, 0600);
637
638static struct attribute *damon_sysfs_scheme_filters_attrs[] = {
639 &damon_sysfs_scheme_filters_nr_attr.attr,
640 NULL,
641};
642ATTRIBUTE_GROUPS(damon_sysfs_scheme_filters);
643
644static const struct kobj_type damon_sysfs_scheme_filters_ktype = {
645 .release = damon_sysfs_scheme_filters_release,
646 .sysfs_ops = &kobj_sysfs_ops,
647 .default_groups = damon_sysfs_scheme_filters_groups,
648};
649
650/*
651 * watermarks directory
652 */
653
654struct damon_sysfs_watermarks {
655 struct kobject kobj;
656 enum damos_wmark_metric metric;
657 unsigned long interval_us;
658 unsigned long high;
659 unsigned long mid;
660 unsigned long low;
661};
662
663static struct damon_sysfs_watermarks *damon_sysfs_watermarks_alloc(
664 enum damos_wmark_metric metric, unsigned long interval_us,
665 unsigned long high, unsigned long mid, unsigned long low)
666{
667 struct damon_sysfs_watermarks *watermarks = kmalloc(
668 sizeof(*watermarks), GFP_KERNEL);
669
670 if (!watermarks)
671 return NULL;
672 watermarks->kobj = (struct kobject){};
673 watermarks->metric = metric;
674 watermarks->interval_us = interval_us;
675 watermarks->high = high;
676 watermarks->mid = mid;
677 watermarks->low = low;
678 return watermarks;
679}
680
681/* Should match with enum damos_wmark_metric */
682static const char * const damon_sysfs_wmark_metric_strs[] = {
683 "none",
684 "free_mem_rate",
685};
686
687static ssize_t metric_show(struct kobject *kobj, struct kobj_attribute *attr,
688 char *buf)
689{
690 struct damon_sysfs_watermarks *watermarks = container_of(kobj,
691 struct damon_sysfs_watermarks, kobj);
692
693 return sysfs_emit(buf, "%s\n",
694 damon_sysfs_wmark_metric_strs[watermarks->metric]);
695}
696
697static ssize_t metric_store(struct kobject *kobj, struct kobj_attribute *attr,
698 const char *buf, size_t count)
699{
700 struct damon_sysfs_watermarks *watermarks = container_of(kobj,
701 struct damon_sysfs_watermarks, kobj);
702 enum damos_wmark_metric metric;
703
704 for (metric = 0; metric < NR_DAMOS_WMARK_METRICS; metric++) {
705 if (sysfs_streq(buf, damon_sysfs_wmark_metric_strs[metric])) {
706 watermarks->metric = metric;
707 return count;
708 }
709 }
710 return -EINVAL;
711}
712
713static ssize_t interval_us_show(struct kobject *kobj,
714 struct kobj_attribute *attr, char *buf)
715{
716 struct damon_sysfs_watermarks *watermarks = container_of(kobj,
717 struct damon_sysfs_watermarks, kobj);
718
719 return sysfs_emit(buf, "%lu\n", watermarks->interval_us);
720}
721
722static ssize_t interval_us_store(struct kobject *kobj,
723 struct kobj_attribute *attr, const char *buf, size_t count)
724{
725 struct damon_sysfs_watermarks *watermarks = container_of(kobj,
726 struct damon_sysfs_watermarks, kobj);
727 int err = kstrtoul(buf, 0, &watermarks->interval_us);
728
729 return err ? err : count;
730}
731
732static ssize_t high_show(struct kobject *kobj,
733 struct kobj_attribute *attr, char *buf)
734{
735 struct damon_sysfs_watermarks *watermarks = container_of(kobj,
736 struct damon_sysfs_watermarks, kobj);
737
738 return sysfs_emit(buf, "%lu\n", watermarks->high);
739}
740
741static ssize_t high_store(struct kobject *kobj,
742 struct kobj_attribute *attr, const char *buf, size_t count)
743{
744 struct damon_sysfs_watermarks *watermarks = container_of(kobj,
745 struct damon_sysfs_watermarks, kobj);
746 int err = kstrtoul(buf, 0, &watermarks->high);
747
748 return err ? err : count;
749}
750
751static ssize_t mid_show(struct kobject *kobj,
752 struct kobj_attribute *attr, char *buf)
753{
754 struct damon_sysfs_watermarks *watermarks = container_of(kobj,
755 struct damon_sysfs_watermarks, kobj);
756
757 return sysfs_emit(buf, "%lu\n", watermarks->mid);
758}
759
760static ssize_t mid_store(struct kobject *kobj,
761 struct kobj_attribute *attr, const char *buf, size_t count)
762{
763 struct damon_sysfs_watermarks *watermarks = container_of(kobj,
764 struct damon_sysfs_watermarks, kobj);
765 int err = kstrtoul(buf, 0, &watermarks->mid);
766
767 return err ? err : count;
768}
769
770static ssize_t low_show(struct kobject *kobj,
771 struct kobj_attribute *attr, char *buf)
772{
773 struct damon_sysfs_watermarks *watermarks = container_of(kobj,
774 struct damon_sysfs_watermarks, kobj);
775
776 return sysfs_emit(buf, "%lu\n", watermarks->low);
777}
778
779static ssize_t low_store(struct kobject *kobj,
780 struct kobj_attribute *attr, const char *buf, size_t count)
781{
782 struct damon_sysfs_watermarks *watermarks = container_of(kobj,
783 struct damon_sysfs_watermarks, kobj);
784 int err = kstrtoul(buf, 0, &watermarks->low);
785
786 return err ? err : count;
787}
788
789static void damon_sysfs_watermarks_release(struct kobject *kobj)
790{
791 kfree(container_of(kobj, struct damon_sysfs_watermarks, kobj));
792}
793
794static struct kobj_attribute damon_sysfs_watermarks_metric_attr =
795 __ATTR_RW_MODE(metric, 0600);
796
797static struct kobj_attribute damon_sysfs_watermarks_interval_us_attr =
798 __ATTR_RW_MODE(interval_us, 0600);
799
800static struct kobj_attribute damon_sysfs_watermarks_high_attr =
801 __ATTR_RW_MODE(high, 0600);
802
803static struct kobj_attribute damon_sysfs_watermarks_mid_attr =
804 __ATTR_RW_MODE(mid, 0600);
805
806static struct kobj_attribute damon_sysfs_watermarks_low_attr =
807 __ATTR_RW_MODE(low, 0600);
808
809static struct attribute *damon_sysfs_watermarks_attrs[] = {
810 &damon_sysfs_watermarks_metric_attr.attr,
811 &damon_sysfs_watermarks_interval_us_attr.attr,
812 &damon_sysfs_watermarks_high_attr.attr,
813 &damon_sysfs_watermarks_mid_attr.attr,
814 &damon_sysfs_watermarks_low_attr.attr,
815 NULL,
816};
817ATTRIBUTE_GROUPS(damon_sysfs_watermarks);
818
819static const struct kobj_type damon_sysfs_watermarks_ktype = {
820 .release = damon_sysfs_watermarks_release,
821 .sysfs_ops = &kobj_sysfs_ops,
822 .default_groups = damon_sysfs_watermarks_groups,
823};
824
825/*
826 * quota goal directory
827 */
828
829struct damos_sysfs_quota_goal {
830 struct kobject kobj;
831 enum damos_quota_goal_metric metric;
832 unsigned long target_value;
833 unsigned long current_value;
834};
835
836/* This should match with enum damos_action */
837static const char * const damos_sysfs_quota_goal_metric_strs[] = {
838 "user_input",
839 "some_mem_psi_us",
840};
841
842static struct damos_sysfs_quota_goal *damos_sysfs_quota_goal_alloc(void)
843{
844 return kzalloc(sizeof(struct damos_sysfs_quota_goal), GFP_KERNEL);
845}
846
847static ssize_t target_metric_show(struct kobject *kobj,
848 struct kobj_attribute *attr, char *buf)
849{
850 struct damos_sysfs_quota_goal *goal = container_of(kobj,
851 struct damos_sysfs_quota_goal, kobj);
852
853 return sysfs_emit(buf, "%s\n",
854 damos_sysfs_quota_goal_metric_strs[goal->metric]);
855}
856
857static ssize_t target_metric_store(struct kobject *kobj,
858 struct kobj_attribute *attr, const char *buf, size_t count)
859{
860 struct damos_sysfs_quota_goal *goal = container_of(kobj,
861 struct damos_sysfs_quota_goal, kobj);
862 enum damos_quota_goal_metric m;
863
864 for (m = 0; m < NR_DAMOS_QUOTA_GOAL_METRICS; m++) {
865 if (sysfs_streq(buf, damos_sysfs_quota_goal_metric_strs[m])) {
866 goal->metric = m;
867 return count;
868 }
869 }
870 return -EINVAL;
871}
872
873static ssize_t target_value_show(struct kobject *kobj,
874 struct kobj_attribute *attr, char *buf)
875{
876 struct damos_sysfs_quota_goal *goal = container_of(kobj, struct
877 damos_sysfs_quota_goal, kobj);
878
879 return sysfs_emit(buf, "%lu\n", goal->target_value);
880}
881
882static ssize_t target_value_store(struct kobject *kobj,
883 struct kobj_attribute *attr, const char *buf, size_t count)
884{
885 struct damos_sysfs_quota_goal *goal = container_of(kobj, struct
886 damos_sysfs_quota_goal, kobj);
887 int err = kstrtoul(buf, 0, &goal->target_value);
888
889 return err ? err : count;
890}
891
892static ssize_t current_value_show(struct kobject *kobj,
893 struct kobj_attribute *attr, char *buf)
894{
895 struct damos_sysfs_quota_goal *goal = container_of(kobj, struct
896 damos_sysfs_quota_goal, kobj);
897
898 return sysfs_emit(buf, "%lu\n", goal->current_value);
899}
900
901static ssize_t current_value_store(struct kobject *kobj,
902 struct kobj_attribute *attr, const char *buf, size_t count)
903{
904 struct damos_sysfs_quota_goal *goal = container_of(kobj, struct
905 damos_sysfs_quota_goal, kobj);
906 int err = kstrtoul(buf, 0, &goal->current_value);
907
908 /* feed callback should check existence of this file and read value */
909 return err ? err : count;
910}
911
912static void damos_sysfs_quota_goal_release(struct kobject *kobj)
913{
914 /* or, notify this release to the feed callback */
915 kfree(container_of(kobj, struct damos_sysfs_quota_goal, kobj));
916}
917
918static struct kobj_attribute damos_sysfs_quota_goal_target_metric_attr =
919 __ATTR_RW_MODE(target_metric, 0600);
920
921static struct kobj_attribute damos_sysfs_quota_goal_target_value_attr =
922 __ATTR_RW_MODE(target_value, 0600);
923
924static struct kobj_attribute damos_sysfs_quota_goal_current_value_attr =
925 __ATTR_RW_MODE(current_value, 0600);
926
927static struct attribute *damos_sysfs_quota_goal_attrs[] = {
928 &damos_sysfs_quota_goal_target_metric_attr.attr,
929 &damos_sysfs_quota_goal_target_value_attr.attr,
930 &damos_sysfs_quota_goal_current_value_attr.attr,
931 NULL,
932};
933ATTRIBUTE_GROUPS(damos_sysfs_quota_goal);
934
935static const struct kobj_type damos_sysfs_quota_goal_ktype = {
936 .release = damos_sysfs_quota_goal_release,
937 .sysfs_ops = &kobj_sysfs_ops,
938 .default_groups = damos_sysfs_quota_goal_groups,
939};
940
941/*
942 * quota goals directory
943 */
944
945struct damos_sysfs_quota_goals {
946 struct kobject kobj;
947 struct damos_sysfs_quota_goal **goals_arr; /* counted by nr */
948 int nr;
949};
950
951static struct damos_sysfs_quota_goals *damos_sysfs_quota_goals_alloc(void)
952{
953 return kzalloc(sizeof(struct damos_sysfs_quota_goals), GFP_KERNEL);
954}
955
956static void damos_sysfs_quota_goals_rm_dirs(
957 struct damos_sysfs_quota_goals *goals)
958{
959 struct damos_sysfs_quota_goal **goals_arr = goals->goals_arr;
960 int i;
961
962 for (i = 0; i < goals->nr; i++)
963 kobject_put(&goals_arr[i]->kobj);
964 goals->nr = 0;
965 kfree(goals_arr);
966 goals->goals_arr = NULL;
967}
968
969static int damos_sysfs_quota_goals_add_dirs(
970 struct damos_sysfs_quota_goals *goals, int nr_goals)
971{
972 struct damos_sysfs_quota_goal **goals_arr, *goal;
973 int err, i;
974
975 damos_sysfs_quota_goals_rm_dirs(goals);
976 if (!nr_goals)
977 return 0;
978
979 goals_arr = kmalloc_array(nr_goals, sizeof(*goals_arr),
980 GFP_KERNEL | __GFP_NOWARN);
981 if (!goals_arr)
982 return -ENOMEM;
983 goals->goals_arr = goals_arr;
984
985 for (i = 0; i < nr_goals; i++) {
986 goal = damos_sysfs_quota_goal_alloc();
987 if (!goal) {
988 damos_sysfs_quota_goals_rm_dirs(goals);
989 return -ENOMEM;
990 }
991
992 err = kobject_init_and_add(&goal->kobj,
993 &damos_sysfs_quota_goal_ktype, &goals->kobj,
994 "%d", i);
995 if (err) {
996 kobject_put(&goal->kobj);
997 damos_sysfs_quota_goals_rm_dirs(goals);
998 return err;
999 }
1000
1001 goals_arr[i] = goal;
1002 goals->nr++;
1003 }
1004 return 0;
1005}
1006
1007static ssize_t nr_goals_show(struct kobject *kobj,
1008 struct kobj_attribute *attr, char *buf)
1009{
1010 struct damos_sysfs_quota_goals *goals = container_of(kobj,
1011 struct damos_sysfs_quota_goals, kobj);
1012
1013 return sysfs_emit(buf, "%d\n", goals->nr);
1014}
1015
1016static ssize_t nr_goals_store(struct kobject *kobj,
1017 struct kobj_attribute *attr, const char *buf, size_t count)
1018{
1019 struct damos_sysfs_quota_goals *goals;
1020 int nr, err = kstrtoint(buf, 0, &nr);
1021
1022 if (err)
1023 return err;
1024 if (nr < 0)
1025 return -EINVAL;
1026
1027 goals = container_of(kobj, struct damos_sysfs_quota_goals, kobj);
1028
1029 if (!mutex_trylock(&damon_sysfs_lock))
1030 return -EBUSY;
1031 err = damos_sysfs_quota_goals_add_dirs(goals, nr);
1032 mutex_unlock(&damon_sysfs_lock);
1033 if (err)
1034 return err;
1035
1036 return count;
1037}
1038
1039static void damos_sysfs_quota_goals_release(struct kobject *kobj)
1040{
1041 kfree(container_of(kobj, struct damos_sysfs_quota_goals, kobj));
1042}
1043
1044static struct kobj_attribute damos_sysfs_quota_goals_nr_attr =
1045 __ATTR_RW_MODE(nr_goals, 0600);
1046
1047static struct attribute *damos_sysfs_quota_goals_attrs[] = {
1048 &damos_sysfs_quota_goals_nr_attr.attr,
1049 NULL,
1050};
1051ATTRIBUTE_GROUPS(damos_sysfs_quota_goals);
1052
1053static const struct kobj_type damos_sysfs_quota_goals_ktype = {
1054 .release = damos_sysfs_quota_goals_release,
1055 .sysfs_ops = &kobj_sysfs_ops,
1056 .default_groups = damos_sysfs_quota_goals_groups,
1057};
1058
1059/*
1060 * scheme/weights directory
1061 */
1062
1063struct damon_sysfs_weights {
1064 struct kobject kobj;
1065 unsigned int sz;
1066 unsigned int nr_accesses;
1067 unsigned int age;
1068};
1069
1070static struct damon_sysfs_weights *damon_sysfs_weights_alloc(unsigned int sz,
1071 unsigned int nr_accesses, unsigned int age)
1072{
1073 struct damon_sysfs_weights *weights = kmalloc(sizeof(*weights),
1074 GFP_KERNEL);
1075
1076 if (!weights)
1077 return NULL;
1078 weights->kobj = (struct kobject){};
1079 weights->sz = sz;
1080 weights->nr_accesses = nr_accesses;
1081 weights->age = age;
1082 return weights;
1083}
1084
1085static ssize_t sz_permil_show(struct kobject *kobj,
1086 struct kobj_attribute *attr, char *buf)
1087{
1088 struct damon_sysfs_weights *weights = container_of(kobj,
1089 struct damon_sysfs_weights, kobj);
1090
1091 return sysfs_emit(buf, "%u\n", weights->sz);
1092}
1093
1094static ssize_t sz_permil_store(struct kobject *kobj,
1095 struct kobj_attribute *attr, const char *buf, size_t count)
1096{
1097 struct damon_sysfs_weights *weights = container_of(kobj,
1098 struct damon_sysfs_weights, kobj);
1099 int err = kstrtouint(buf, 0, &weights->sz);
1100
1101 return err ? err : count;
1102}
1103
1104static ssize_t nr_accesses_permil_show(struct kobject *kobj,
1105 struct kobj_attribute *attr, char *buf)
1106{
1107 struct damon_sysfs_weights *weights = container_of(kobj,
1108 struct damon_sysfs_weights, kobj);
1109
1110 return sysfs_emit(buf, "%u\n", weights->nr_accesses);
1111}
1112
1113static ssize_t nr_accesses_permil_store(struct kobject *kobj,
1114 struct kobj_attribute *attr, const char *buf, size_t count)
1115{
1116 struct damon_sysfs_weights *weights = container_of(kobj,
1117 struct damon_sysfs_weights, kobj);
1118 int err = kstrtouint(buf, 0, &weights->nr_accesses);
1119
1120 return err ? err : count;
1121}
1122
1123static ssize_t age_permil_show(struct kobject *kobj,
1124 struct kobj_attribute *attr, char *buf)
1125{
1126 struct damon_sysfs_weights *weights = container_of(kobj,
1127 struct damon_sysfs_weights, kobj);
1128
1129 return sysfs_emit(buf, "%u\n", weights->age);
1130}
1131
1132static ssize_t age_permil_store(struct kobject *kobj,
1133 struct kobj_attribute *attr, const char *buf, size_t count)
1134{
1135 struct damon_sysfs_weights *weights = container_of(kobj,
1136 struct damon_sysfs_weights, kobj);
1137 int err = kstrtouint(buf, 0, &weights->age);
1138
1139 return err ? err : count;
1140}
1141
1142static void damon_sysfs_weights_release(struct kobject *kobj)
1143{
1144 kfree(container_of(kobj, struct damon_sysfs_weights, kobj));
1145}
1146
1147static struct kobj_attribute damon_sysfs_weights_sz_attr =
1148 __ATTR_RW_MODE(sz_permil, 0600);
1149
1150static struct kobj_attribute damon_sysfs_weights_nr_accesses_attr =
1151 __ATTR_RW_MODE(nr_accesses_permil, 0600);
1152
1153static struct kobj_attribute damon_sysfs_weights_age_attr =
1154 __ATTR_RW_MODE(age_permil, 0600);
1155
1156static struct attribute *damon_sysfs_weights_attrs[] = {
1157 &damon_sysfs_weights_sz_attr.attr,
1158 &damon_sysfs_weights_nr_accesses_attr.attr,
1159 &damon_sysfs_weights_age_attr.attr,
1160 NULL,
1161};
1162ATTRIBUTE_GROUPS(damon_sysfs_weights);
1163
1164static const struct kobj_type damon_sysfs_weights_ktype = {
1165 .release = damon_sysfs_weights_release,
1166 .sysfs_ops = &kobj_sysfs_ops,
1167 .default_groups = damon_sysfs_weights_groups,
1168};
1169
1170/*
1171 * quotas directory
1172 */
1173
1174struct damon_sysfs_quotas {
1175 struct kobject kobj;
1176 struct damon_sysfs_weights *weights;
1177 struct damos_sysfs_quota_goals *goals;
1178 unsigned long ms;
1179 unsigned long sz;
1180 unsigned long reset_interval_ms;
1181 unsigned long effective_sz; /* Effective size quota in bytes */
1182};
1183
1184static struct damon_sysfs_quotas *damon_sysfs_quotas_alloc(void)
1185{
1186 return kzalloc(sizeof(struct damon_sysfs_quotas), GFP_KERNEL);
1187}
1188
1189static int damon_sysfs_quotas_add_dirs(struct damon_sysfs_quotas *quotas)
1190{
1191 struct damon_sysfs_weights *weights;
1192 struct damos_sysfs_quota_goals *goals;
1193 int err;
1194
1195 weights = damon_sysfs_weights_alloc(0, 0, 0);
1196 if (!weights)
1197 return -ENOMEM;
1198
1199 err = kobject_init_and_add(&weights->kobj, &damon_sysfs_weights_ktype,
1200 "as->kobj, "weights");
1201 if (err) {
1202 kobject_put(&weights->kobj);
1203 return err;
1204 }
1205 quotas->weights = weights;
1206
1207 goals = damos_sysfs_quota_goals_alloc();
1208 if (!goals) {
1209 kobject_put(&weights->kobj);
1210 return -ENOMEM;
1211 }
1212 err = kobject_init_and_add(&goals->kobj,
1213 &damos_sysfs_quota_goals_ktype, "as->kobj,
1214 "goals");
1215 if (err) {
1216 kobject_put(&weights->kobj);
1217 kobject_put(&goals->kobj);
1218 } else {
1219 quotas->goals = goals;
1220 }
1221
1222 return err;
1223}
1224
1225static void damon_sysfs_quotas_rm_dirs(struct damon_sysfs_quotas *quotas)
1226{
1227 kobject_put("as->weights->kobj);
1228 damos_sysfs_quota_goals_rm_dirs(quotas->goals);
1229 kobject_put("as->goals->kobj);
1230}
1231
1232static ssize_t ms_show(struct kobject *kobj, struct kobj_attribute *attr,
1233 char *buf)
1234{
1235 struct damon_sysfs_quotas *quotas = container_of(kobj,
1236 struct damon_sysfs_quotas, kobj);
1237
1238 return sysfs_emit(buf, "%lu\n", quotas->ms);
1239}
1240
1241static ssize_t ms_store(struct kobject *kobj, struct kobj_attribute *attr,
1242 const char *buf, size_t count)
1243{
1244 struct damon_sysfs_quotas *quotas = container_of(kobj,
1245 struct damon_sysfs_quotas, kobj);
1246 int err = kstrtoul(buf, 0, "as->ms);
1247
1248 if (err)
1249 return -EINVAL;
1250 return count;
1251}
1252
1253static ssize_t bytes_show(struct kobject *kobj, struct kobj_attribute *attr,
1254 char *buf)
1255{
1256 struct damon_sysfs_quotas *quotas = container_of(kobj,
1257 struct damon_sysfs_quotas, kobj);
1258
1259 return sysfs_emit(buf, "%lu\n", quotas->sz);
1260}
1261
1262static ssize_t bytes_store(struct kobject *kobj,
1263 struct kobj_attribute *attr, const char *buf, size_t count)
1264{
1265 struct damon_sysfs_quotas *quotas = container_of(kobj,
1266 struct damon_sysfs_quotas, kobj);
1267 int err = kstrtoul(buf, 0, "as->sz);
1268
1269 if (err)
1270 return -EINVAL;
1271 return count;
1272}
1273
1274static ssize_t reset_interval_ms_show(struct kobject *kobj,
1275 struct kobj_attribute *attr, char *buf)
1276{
1277 struct damon_sysfs_quotas *quotas = container_of(kobj,
1278 struct damon_sysfs_quotas, kobj);
1279
1280 return sysfs_emit(buf, "%lu\n", quotas->reset_interval_ms);
1281}
1282
1283static ssize_t reset_interval_ms_store(struct kobject *kobj,
1284 struct kobj_attribute *attr, const char *buf, size_t count)
1285{
1286 struct damon_sysfs_quotas *quotas = container_of(kobj,
1287 struct damon_sysfs_quotas, kobj);
1288 int err = kstrtoul(buf, 0, "as->reset_interval_ms);
1289
1290 if (err)
1291 return -EINVAL;
1292 return count;
1293}
1294
1295static ssize_t effective_bytes_show(struct kobject *kobj,
1296 struct kobj_attribute *attr, char *buf)
1297{
1298 struct damon_sysfs_quotas *quotas = container_of(kobj,
1299 struct damon_sysfs_quotas, kobj);
1300
1301 return sysfs_emit(buf, "%lu\n", quotas->effective_sz);
1302}
1303
1304static void damon_sysfs_quotas_release(struct kobject *kobj)
1305{
1306 kfree(container_of(kobj, struct damon_sysfs_quotas, kobj));
1307}
1308
1309static struct kobj_attribute damon_sysfs_quotas_ms_attr =
1310 __ATTR_RW_MODE(ms, 0600);
1311
1312static struct kobj_attribute damon_sysfs_quotas_sz_attr =
1313 __ATTR_RW_MODE(bytes, 0600);
1314
1315static struct kobj_attribute damon_sysfs_quotas_reset_interval_ms_attr =
1316 __ATTR_RW_MODE(reset_interval_ms, 0600);
1317
1318static struct kobj_attribute damon_sysfs_quotas_effective_bytes_attr =
1319 __ATTR_RO_MODE(effective_bytes, 0400);
1320
1321static struct attribute *damon_sysfs_quotas_attrs[] = {
1322 &damon_sysfs_quotas_ms_attr.attr,
1323 &damon_sysfs_quotas_sz_attr.attr,
1324 &damon_sysfs_quotas_reset_interval_ms_attr.attr,
1325 &damon_sysfs_quotas_effective_bytes_attr.attr,
1326 NULL,
1327};
1328ATTRIBUTE_GROUPS(damon_sysfs_quotas);
1329
1330static const struct kobj_type damon_sysfs_quotas_ktype = {
1331 .release = damon_sysfs_quotas_release,
1332 .sysfs_ops = &kobj_sysfs_ops,
1333 .default_groups = damon_sysfs_quotas_groups,
1334};
1335
1336/*
1337 * access_pattern directory
1338 */
1339
1340struct damon_sysfs_access_pattern {
1341 struct kobject kobj;
1342 struct damon_sysfs_ul_range *sz;
1343 struct damon_sysfs_ul_range *nr_accesses;
1344 struct damon_sysfs_ul_range *age;
1345};
1346
1347static
1348struct damon_sysfs_access_pattern *damon_sysfs_access_pattern_alloc(void)
1349{
1350 struct damon_sysfs_access_pattern *access_pattern =
1351 kmalloc(sizeof(*access_pattern), GFP_KERNEL);
1352
1353 if (!access_pattern)
1354 return NULL;
1355 access_pattern->kobj = (struct kobject){};
1356 return access_pattern;
1357}
1358
1359static int damon_sysfs_access_pattern_add_range_dir(
1360 struct damon_sysfs_access_pattern *access_pattern,
1361 struct damon_sysfs_ul_range **range_dir_ptr,
1362 char *name)
1363{
1364 struct damon_sysfs_ul_range *range = damon_sysfs_ul_range_alloc(0, 0);
1365 int err;
1366
1367 if (!range)
1368 return -ENOMEM;
1369 err = kobject_init_and_add(&range->kobj, &damon_sysfs_ul_range_ktype,
1370 &access_pattern->kobj, name);
1371 if (err)
1372 kobject_put(&range->kobj);
1373 else
1374 *range_dir_ptr = range;
1375 return err;
1376}
1377
1378static int damon_sysfs_access_pattern_add_dirs(
1379 struct damon_sysfs_access_pattern *access_pattern)
1380{
1381 int err;
1382
1383 err = damon_sysfs_access_pattern_add_range_dir(access_pattern,
1384 &access_pattern->sz, "sz");
1385 if (err)
1386 goto put_sz_out;
1387
1388 err = damon_sysfs_access_pattern_add_range_dir(access_pattern,
1389 &access_pattern->nr_accesses, "nr_accesses");
1390 if (err)
1391 goto put_nr_accesses_sz_out;
1392
1393 err = damon_sysfs_access_pattern_add_range_dir(access_pattern,
1394 &access_pattern->age, "age");
1395 if (err)
1396 goto put_age_nr_accesses_sz_out;
1397 return 0;
1398
1399put_age_nr_accesses_sz_out:
1400 kobject_put(&access_pattern->age->kobj);
1401 access_pattern->age = NULL;
1402put_nr_accesses_sz_out:
1403 kobject_put(&access_pattern->nr_accesses->kobj);
1404 access_pattern->nr_accesses = NULL;
1405put_sz_out:
1406 kobject_put(&access_pattern->sz->kobj);
1407 access_pattern->sz = NULL;
1408 return err;
1409}
1410
1411static void damon_sysfs_access_pattern_rm_dirs(
1412 struct damon_sysfs_access_pattern *access_pattern)
1413{
1414 kobject_put(&access_pattern->sz->kobj);
1415 kobject_put(&access_pattern->nr_accesses->kobj);
1416 kobject_put(&access_pattern->age->kobj);
1417}
1418
1419static void damon_sysfs_access_pattern_release(struct kobject *kobj)
1420{
1421 kfree(container_of(kobj, struct damon_sysfs_access_pattern, kobj));
1422}
1423
1424static struct attribute *damon_sysfs_access_pattern_attrs[] = {
1425 NULL,
1426};
1427ATTRIBUTE_GROUPS(damon_sysfs_access_pattern);
1428
1429static const struct kobj_type damon_sysfs_access_pattern_ktype = {
1430 .release = damon_sysfs_access_pattern_release,
1431 .sysfs_ops = &kobj_sysfs_ops,
1432 .default_groups = damon_sysfs_access_pattern_groups,
1433};
1434
1435/*
1436 * scheme directory
1437 */
1438
1439struct damon_sysfs_scheme {
1440 struct kobject kobj;
1441 enum damos_action action;
1442 struct damon_sysfs_access_pattern *access_pattern;
1443 unsigned long apply_interval_us;
1444 struct damon_sysfs_quotas *quotas;
1445 struct damon_sysfs_watermarks *watermarks;
1446 struct damon_sysfs_scheme_filters *filters;
1447 struct damon_sysfs_stats *stats;
1448 struct damon_sysfs_scheme_regions *tried_regions;
1449 int target_nid;
1450};
1451
1452/* This should match with enum damos_action */
1453static const char * const damon_sysfs_damos_action_strs[] = {
1454 "willneed",
1455 "cold",
1456 "pageout",
1457 "hugepage",
1458 "nohugepage",
1459 "lru_prio",
1460 "lru_deprio",
1461 "migrate_hot",
1462 "migrate_cold",
1463 "stat",
1464};
1465
1466static struct damon_sysfs_scheme *damon_sysfs_scheme_alloc(
1467 enum damos_action action, unsigned long apply_interval_us)
1468{
1469 struct damon_sysfs_scheme *scheme = kmalloc(sizeof(*scheme),
1470 GFP_KERNEL);
1471
1472 if (!scheme)
1473 return NULL;
1474 scheme->kobj = (struct kobject){};
1475 scheme->action = action;
1476 scheme->apply_interval_us = apply_interval_us;
1477 scheme->target_nid = NUMA_NO_NODE;
1478 return scheme;
1479}
1480
1481static int damon_sysfs_scheme_set_access_pattern(
1482 struct damon_sysfs_scheme *scheme)
1483{
1484 struct damon_sysfs_access_pattern *access_pattern;
1485 int err;
1486
1487 access_pattern = damon_sysfs_access_pattern_alloc();
1488 if (!access_pattern)
1489 return -ENOMEM;
1490 err = kobject_init_and_add(&access_pattern->kobj,
1491 &damon_sysfs_access_pattern_ktype, &scheme->kobj,
1492 "access_pattern");
1493 if (err)
1494 goto out;
1495 err = damon_sysfs_access_pattern_add_dirs(access_pattern);
1496 if (err)
1497 goto out;
1498 scheme->access_pattern = access_pattern;
1499 return 0;
1500
1501out:
1502 kobject_put(&access_pattern->kobj);
1503 return err;
1504}
1505
1506static int damon_sysfs_scheme_set_quotas(struct damon_sysfs_scheme *scheme)
1507{
1508 struct damon_sysfs_quotas *quotas = damon_sysfs_quotas_alloc();
1509 int err;
1510
1511 if (!quotas)
1512 return -ENOMEM;
1513 err = kobject_init_and_add("as->kobj, &damon_sysfs_quotas_ktype,
1514 &scheme->kobj, "quotas");
1515 if (err)
1516 goto out;
1517 err = damon_sysfs_quotas_add_dirs(quotas);
1518 if (err)
1519 goto out;
1520 scheme->quotas = quotas;
1521 return 0;
1522
1523out:
1524 kobject_put("as->kobj);
1525 return err;
1526}
1527
1528static int damon_sysfs_scheme_set_watermarks(struct damon_sysfs_scheme *scheme)
1529{
1530 struct damon_sysfs_watermarks *watermarks =
1531 damon_sysfs_watermarks_alloc(DAMOS_WMARK_NONE, 0, 0, 0, 0);
1532 int err;
1533
1534 if (!watermarks)
1535 return -ENOMEM;
1536 err = kobject_init_and_add(&watermarks->kobj,
1537 &damon_sysfs_watermarks_ktype, &scheme->kobj,
1538 "watermarks");
1539 if (err)
1540 kobject_put(&watermarks->kobj);
1541 else
1542 scheme->watermarks = watermarks;
1543 return err;
1544}
1545
1546static int damon_sysfs_scheme_set_filters(struct damon_sysfs_scheme *scheme)
1547{
1548 struct damon_sysfs_scheme_filters *filters =
1549 damon_sysfs_scheme_filters_alloc();
1550 int err;
1551
1552 if (!filters)
1553 return -ENOMEM;
1554 err = kobject_init_and_add(&filters->kobj,
1555 &damon_sysfs_scheme_filters_ktype, &scheme->kobj,
1556 "filters");
1557 if (err)
1558 kobject_put(&filters->kobj);
1559 else
1560 scheme->filters = filters;
1561 return err;
1562}
1563
1564static int damon_sysfs_scheme_set_stats(struct damon_sysfs_scheme *scheme)
1565{
1566 struct damon_sysfs_stats *stats = damon_sysfs_stats_alloc();
1567 int err;
1568
1569 if (!stats)
1570 return -ENOMEM;
1571 err = kobject_init_and_add(&stats->kobj, &damon_sysfs_stats_ktype,
1572 &scheme->kobj, "stats");
1573 if (err)
1574 kobject_put(&stats->kobj);
1575 else
1576 scheme->stats = stats;
1577 return err;
1578}
1579
1580static int damon_sysfs_scheme_set_tried_regions(
1581 struct damon_sysfs_scheme *scheme)
1582{
1583 struct damon_sysfs_scheme_regions *tried_regions =
1584 damon_sysfs_scheme_regions_alloc();
1585 int err;
1586
1587 if (!tried_regions)
1588 return -ENOMEM;
1589 err = kobject_init_and_add(&tried_regions->kobj,
1590 &damon_sysfs_scheme_regions_ktype, &scheme->kobj,
1591 "tried_regions");
1592 if (err)
1593 kobject_put(&tried_regions->kobj);
1594 else
1595 scheme->tried_regions = tried_regions;
1596 return err;
1597}
1598
1599static int damon_sysfs_scheme_add_dirs(struct damon_sysfs_scheme *scheme)
1600{
1601 int err;
1602
1603 err = damon_sysfs_scheme_set_access_pattern(scheme);
1604 if (err)
1605 return err;
1606 err = damon_sysfs_scheme_set_quotas(scheme);
1607 if (err)
1608 goto put_access_pattern_out;
1609 err = damon_sysfs_scheme_set_watermarks(scheme);
1610 if (err)
1611 goto put_quotas_access_pattern_out;
1612 err = damon_sysfs_scheme_set_filters(scheme);
1613 if (err)
1614 goto put_watermarks_quotas_access_pattern_out;
1615 err = damon_sysfs_scheme_set_stats(scheme);
1616 if (err)
1617 goto put_filters_watermarks_quotas_access_pattern_out;
1618 err = damon_sysfs_scheme_set_tried_regions(scheme);
1619 if (err)
1620 goto put_tried_regions_out;
1621 return 0;
1622
1623put_tried_regions_out:
1624 kobject_put(&scheme->tried_regions->kobj);
1625 scheme->tried_regions = NULL;
1626put_filters_watermarks_quotas_access_pattern_out:
1627 kobject_put(&scheme->filters->kobj);
1628 scheme->filters = NULL;
1629put_watermarks_quotas_access_pattern_out:
1630 kobject_put(&scheme->watermarks->kobj);
1631 scheme->watermarks = NULL;
1632put_quotas_access_pattern_out:
1633 kobject_put(&scheme->quotas->kobj);
1634 scheme->quotas = NULL;
1635put_access_pattern_out:
1636 kobject_put(&scheme->access_pattern->kobj);
1637 scheme->access_pattern = NULL;
1638 return err;
1639}
1640
1641static void damon_sysfs_scheme_rm_dirs(struct damon_sysfs_scheme *scheme)
1642{
1643 damon_sysfs_access_pattern_rm_dirs(scheme->access_pattern);
1644 kobject_put(&scheme->access_pattern->kobj);
1645 damon_sysfs_quotas_rm_dirs(scheme->quotas);
1646 kobject_put(&scheme->quotas->kobj);
1647 kobject_put(&scheme->watermarks->kobj);
1648 damon_sysfs_scheme_filters_rm_dirs(scheme->filters);
1649 kobject_put(&scheme->filters->kobj);
1650 kobject_put(&scheme->stats->kobj);
1651 damon_sysfs_scheme_regions_rm_dirs(scheme->tried_regions);
1652 kobject_put(&scheme->tried_regions->kobj);
1653}
1654
1655static ssize_t action_show(struct kobject *kobj, struct kobj_attribute *attr,
1656 char *buf)
1657{
1658 struct damon_sysfs_scheme *scheme = container_of(kobj,
1659 struct damon_sysfs_scheme, kobj);
1660
1661 return sysfs_emit(buf, "%s\n",
1662 damon_sysfs_damos_action_strs[scheme->action]);
1663}
1664
1665static ssize_t action_store(struct kobject *kobj, struct kobj_attribute *attr,
1666 const char *buf, size_t count)
1667{
1668 struct damon_sysfs_scheme *scheme = container_of(kobj,
1669 struct damon_sysfs_scheme, kobj);
1670 enum damos_action action;
1671
1672 for (action = 0; action < NR_DAMOS_ACTIONS; action++) {
1673 if (sysfs_streq(buf, damon_sysfs_damos_action_strs[action])) {
1674 scheme->action = action;
1675 return count;
1676 }
1677 }
1678 return -EINVAL;
1679}
1680
1681static ssize_t apply_interval_us_show(struct kobject *kobj,
1682 struct kobj_attribute *attr, char *buf)
1683{
1684 struct damon_sysfs_scheme *scheme = container_of(kobj,
1685 struct damon_sysfs_scheme, kobj);
1686
1687 return sysfs_emit(buf, "%lu\n", scheme->apply_interval_us);
1688}
1689
1690static ssize_t apply_interval_us_store(struct kobject *kobj,
1691 struct kobj_attribute *attr, const char *buf, size_t count)
1692{
1693 struct damon_sysfs_scheme *scheme = container_of(kobj,
1694 struct damon_sysfs_scheme, kobj);
1695 int err = kstrtoul(buf, 0, &scheme->apply_interval_us);
1696
1697 return err ? err : count;
1698}
1699
1700static ssize_t target_nid_show(struct kobject *kobj,
1701 struct kobj_attribute *attr, char *buf)
1702{
1703 struct damon_sysfs_scheme *scheme = container_of(kobj,
1704 struct damon_sysfs_scheme, kobj);
1705
1706 return sysfs_emit(buf, "%d\n", scheme->target_nid);
1707}
1708
1709static ssize_t target_nid_store(struct kobject *kobj,
1710 struct kobj_attribute *attr, const char *buf, size_t count)
1711{
1712 struct damon_sysfs_scheme *scheme = container_of(kobj,
1713 struct damon_sysfs_scheme, kobj);
1714 int err = 0;
1715
1716 /* TODO: error handling for target_nid range. */
1717 err = kstrtoint(buf, 0, &scheme->target_nid);
1718
1719 return err ? err : count;
1720}
1721
1722static void damon_sysfs_scheme_release(struct kobject *kobj)
1723{
1724 kfree(container_of(kobj, struct damon_sysfs_scheme, kobj));
1725}
1726
1727static struct kobj_attribute damon_sysfs_scheme_action_attr =
1728 __ATTR_RW_MODE(action, 0600);
1729
1730static struct kobj_attribute damon_sysfs_scheme_apply_interval_us_attr =
1731 __ATTR_RW_MODE(apply_interval_us, 0600);
1732
1733static struct kobj_attribute damon_sysfs_scheme_target_nid_attr =
1734 __ATTR_RW_MODE(target_nid, 0600);
1735
1736static struct attribute *damon_sysfs_scheme_attrs[] = {
1737 &damon_sysfs_scheme_action_attr.attr,
1738 &damon_sysfs_scheme_apply_interval_us_attr.attr,
1739 &damon_sysfs_scheme_target_nid_attr.attr,
1740 NULL,
1741};
1742ATTRIBUTE_GROUPS(damon_sysfs_scheme);
1743
1744static const struct kobj_type damon_sysfs_scheme_ktype = {
1745 .release = damon_sysfs_scheme_release,
1746 .sysfs_ops = &kobj_sysfs_ops,
1747 .default_groups = damon_sysfs_scheme_groups,
1748};
1749
1750/*
1751 * schemes directory
1752 */
1753
1754struct damon_sysfs_schemes *damon_sysfs_schemes_alloc(void)
1755{
1756 return kzalloc(sizeof(struct damon_sysfs_schemes), GFP_KERNEL);
1757}
1758
1759void damon_sysfs_schemes_rm_dirs(struct damon_sysfs_schemes *schemes)
1760{
1761 struct damon_sysfs_scheme **schemes_arr = schemes->schemes_arr;
1762 int i;
1763
1764 for (i = 0; i < schemes->nr; i++) {
1765 damon_sysfs_scheme_rm_dirs(schemes_arr[i]);
1766 kobject_put(&schemes_arr[i]->kobj);
1767 }
1768 schemes->nr = 0;
1769 kfree(schemes_arr);
1770 schemes->schemes_arr = NULL;
1771}
1772
1773static int damon_sysfs_schemes_add_dirs(struct damon_sysfs_schemes *schemes,
1774 int nr_schemes)
1775{
1776 struct damon_sysfs_scheme **schemes_arr, *scheme;
1777 int err, i;
1778
1779 damon_sysfs_schemes_rm_dirs(schemes);
1780 if (!nr_schemes)
1781 return 0;
1782
1783 schemes_arr = kmalloc_array(nr_schemes, sizeof(*schemes_arr),
1784 GFP_KERNEL | __GFP_NOWARN);
1785 if (!schemes_arr)
1786 return -ENOMEM;
1787 schemes->schemes_arr = schemes_arr;
1788
1789 for (i = 0; i < nr_schemes; i++) {
1790 /*
1791 * apply_interval_us as 0 means same to aggregation interval
1792 * (same to before-apply_interval behavior)
1793 */
1794 scheme = damon_sysfs_scheme_alloc(DAMOS_STAT, 0);
1795 if (!scheme) {
1796 damon_sysfs_schemes_rm_dirs(schemes);
1797 return -ENOMEM;
1798 }
1799
1800 err = kobject_init_and_add(&scheme->kobj,
1801 &damon_sysfs_scheme_ktype, &schemes->kobj,
1802 "%d", i);
1803 if (err)
1804 goto out;
1805 err = damon_sysfs_scheme_add_dirs(scheme);
1806 if (err)
1807 goto out;
1808
1809 schemes_arr[i] = scheme;
1810 schemes->nr++;
1811 }
1812 return 0;
1813
1814out:
1815 damon_sysfs_schemes_rm_dirs(schemes);
1816 kobject_put(&scheme->kobj);
1817 return err;
1818}
1819
1820static ssize_t nr_schemes_show(struct kobject *kobj,
1821 struct kobj_attribute *attr, char *buf)
1822{
1823 struct damon_sysfs_schemes *schemes = container_of(kobj,
1824 struct damon_sysfs_schemes, kobj);
1825
1826 return sysfs_emit(buf, "%d\n", schemes->nr);
1827}
1828
1829static ssize_t nr_schemes_store(struct kobject *kobj,
1830 struct kobj_attribute *attr, const char *buf, size_t count)
1831{
1832 struct damon_sysfs_schemes *schemes;
1833 int nr, err = kstrtoint(buf, 0, &nr);
1834
1835 if (err)
1836 return err;
1837 if (nr < 0)
1838 return -EINVAL;
1839
1840 schemes = container_of(kobj, struct damon_sysfs_schemes, kobj);
1841
1842 if (!mutex_trylock(&damon_sysfs_lock))
1843 return -EBUSY;
1844 err = damon_sysfs_schemes_add_dirs(schemes, nr);
1845 mutex_unlock(&damon_sysfs_lock);
1846 if (err)
1847 return err;
1848 return count;
1849}
1850
1851static void damon_sysfs_schemes_release(struct kobject *kobj)
1852{
1853 kfree(container_of(kobj, struct damon_sysfs_schemes, kobj));
1854}
1855
1856static struct kobj_attribute damon_sysfs_schemes_nr_attr =
1857 __ATTR_RW_MODE(nr_schemes, 0600);
1858
1859static struct attribute *damon_sysfs_schemes_attrs[] = {
1860 &damon_sysfs_schemes_nr_attr.attr,
1861 NULL,
1862};
1863ATTRIBUTE_GROUPS(damon_sysfs_schemes);
1864
1865const struct kobj_type damon_sysfs_schemes_ktype = {
1866 .release = damon_sysfs_schemes_release,
1867 .sysfs_ops = &kobj_sysfs_ops,
1868 .default_groups = damon_sysfs_schemes_groups,
1869};
1870
1871static bool damon_sysfs_memcg_path_eq(struct mem_cgroup *memcg,
1872 char *memcg_path_buf, char *path)
1873{
1874#ifdef CONFIG_MEMCG
1875 cgroup_path(memcg->css.cgroup, memcg_path_buf, PATH_MAX);
1876 if (sysfs_streq(memcg_path_buf, path))
1877 return true;
1878#endif /* CONFIG_MEMCG */
1879 return false;
1880}
1881
1882static int damon_sysfs_memcg_path_to_id(char *memcg_path, unsigned short *id)
1883{
1884 struct mem_cgroup *memcg;
1885 char *path;
1886 bool found = false;
1887
1888 if (!memcg_path)
1889 return -EINVAL;
1890
1891 path = kmalloc(sizeof(*path) * PATH_MAX, GFP_KERNEL);
1892 if (!path)
1893 return -ENOMEM;
1894
1895 for (memcg = mem_cgroup_iter(NULL, NULL, NULL); memcg;
1896 memcg = mem_cgroup_iter(NULL, memcg, NULL)) {
1897 /* skip removed memcg */
1898 if (!mem_cgroup_id(memcg))
1899 continue;
1900 if (damon_sysfs_memcg_path_eq(memcg, path, memcg_path)) {
1901 *id = mem_cgroup_id(memcg);
1902 found = true;
1903 break;
1904 }
1905 }
1906
1907 kfree(path);
1908 return found ? 0 : -EINVAL;
1909}
1910
1911static int damon_sysfs_add_scheme_filters(struct damos *scheme,
1912 struct damon_sysfs_scheme_filters *sysfs_filters)
1913{
1914 int i;
1915
1916 for (i = 0; i < sysfs_filters->nr; i++) {
1917 struct damon_sysfs_scheme_filter *sysfs_filter =
1918 sysfs_filters->filters_arr[i];
1919 struct damos_filter *filter =
1920 damos_new_filter(sysfs_filter->type,
1921 sysfs_filter->matching);
1922 int err;
1923
1924 if (!filter)
1925 return -ENOMEM;
1926 if (filter->type == DAMOS_FILTER_TYPE_MEMCG) {
1927 err = damon_sysfs_memcg_path_to_id(
1928 sysfs_filter->memcg_path,
1929 &filter->memcg_id);
1930 if (err) {
1931 damos_destroy_filter(filter);
1932 return err;
1933 }
1934 } else if (filter->type == DAMOS_FILTER_TYPE_ADDR) {
1935 if (sysfs_filter->addr_range.end <
1936 sysfs_filter->addr_range.start) {
1937 damos_destroy_filter(filter);
1938 return -EINVAL;
1939 }
1940 filter->addr_range = sysfs_filter->addr_range;
1941 } else if (filter->type == DAMOS_FILTER_TYPE_TARGET) {
1942 filter->target_idx = sysfs_filter->target_idx;
1943 }
1944
1945 damos_add_filter(scheme, filter);
1946 }
1947 return 0;
1948}
1949
1950static int damos_sysfs_add_quota_score(
1951 struct damos_sysfs_quota_goals *sysfs_goals,
1952 struct damos_quota *quota)
1953{
1954 struct damos_quota_goal *goal;
1955 int i;
1956
1957 for (i = 0; i < sysfs_goals->nr; i++) {
1958 struct damos_sysfs_quota_goal *sysfs_goal =
1959 sysfs_goals->goals_arr[i];
1960
1961 if (!sysfs_goal->target_value)
1962 continue;
1963
1964 goal = damos_new_quota_goal(sysfs_goal->metric,
1965 sysfs_goal->target_value);
1966 if (!goal)
1967 return -ENOMEM;
1968 if (sysfs_goal->metric == DAMOS_QUOTA_USER_INPUT)
1969 goal->current_value = sysfs_goal->current_value;
1970 damos_add_quota_goal(quota, goal);
1971 }
1972 return 0;
1973}
1974
1975int damos_sysfs_set_quota_scores(struct damon_sysfs_schemes *sysfs_schemes,
1976 struct damon_ctx *ctx)
1977{
1978 struct damos *scheme;
1979 struct damos_quota quota = {};
1980 int i = 0;
1981
1982 INIT_LIST_HEAD("a.goals);
1983 damon_for_each_scheme(scheme, ctx) {
1984 struct damon_sysfs_scheme *sysfs_scheme;
1985 struct damos_quota_goal *g, *g_next;
1986 int err;
1987
1988 /* user could have removed the scheme sysfs dir */
1989 if (i >= sysfs_schemes->nr)
1990 break;
1991
1992 sysfs_scheme = sysfs_schemes->schemes_arr[i];
1993 err = damos_sysfs_add_quota_score(sysfs_scheme->quotas->goals,
1994 "a);
1995 if (err) {
1996 damos_for_each_quota_goal_safe(g, g_next, "a)
1997 damos_destroy_quota_goal(g);
1998 return err;
1999 }
2000 err = damos_commit_quota_goals(&scheme->quota, "a);
2001 damos_for_each_quota_goal_safe(g, g_next, "a)
2002 damos_destroy_quota_goal(g);
2003 if (err)
2004 return err;
2005 i++;
2006 }
2007 return 0;
2008}
2009
2010void damos_sysfs_update_effective_quotas(
2011 struct damon_sysfs_schemes *sysfs_schemes,
2012 struct damon_ctx *ctx)
2013{
2014 struct damos *scheme;
2015 int schemes_idx = 0;
2016
2017 damon_for_each_scheme(scheme, ctx) {
2018 struct damon_sysfs_quotas *sysfs_quotas;
2019
2020 /* user could have removed the scheme sysfs dir */
2021 if (schemes_idx >= sysfs_schemes->nr)
2022 break;
2023
2024 sysfs_quotas =
2025 sysfs_schemes->schemes_arr[schemes_idx++]->quotas;
2026 sysfs_quotas->effective_sz = scheme->quota.esz;
2027 }
2028}
2029
2030static struct damos *damon_sysfs_mk_scheme(
2031 struct damon_sysfs_scheme *sysfs_scheme)
2032{
2033 struct damon_sysfs_access_pattern *access_pattern =
2034 sysfs_scheme->access_pattern;
2035 struct damon_sysfs_quotas *sysfs_quotas = sysfs_scheme->quotas;
2036 struct damon_sysfs_weights *sysfs_weights = sysfs_quotas->weights;
2037 struct damon_sysfs_watermarks *sysfs_wmarks = sysfs_scheme->watermarks;
2038 struct damon_sysfs_scheme_filters *sysfs_filters =
2039 sysfs_scheme->filters;
2040 struct damos *scheme;
2041 int err;
2042
2043 struct damos_access_pattern pattern = {
2044 .min_sz_region = access_pattern->sz->min,
2045 .max_sz_region = access_pattern->sz->max,
2046 .min_nr_accesses = access_pattern->nr_accesses->min,
2047 .max_nr_accesses = access_pattern->nr_accesses->max,
2048 .min_age_region = access_pattern->age->min,
2049 .max_age_region = access_pattern->age->max,
2050 };
2051 struct damos_quota quota = {
2052 .ms = sysfs_quotas->ms,
2053 .sz = sysfs_quotas->sz,
2054 .reset_interval = sysfs_quotas->reset_interval_ms,
2055 .weight_sz = sysfs_weights->sz,
2056 .weight_nr_accesses = sysfs_weights->nr_accesses,
2057 .weight_age = sysfs_weights->age,
2058 };
2059 struct damos_watermarks wmarks = {
2060 .metric = sysfs_wmarks->metric,
2061 .interval = sysfs_wmarks->interval_us,
2062 .high = sysfs_wmarks->high,
2063 .mid = sysfs_wmarks->mid,
2064 .low = sysfs_wmarks->low,
2065 };
2066
2067 scheme = damon_new_scheme(&pattern, sysfs_scheme->action,
2068 sysfs_scheme->apply_interval_us, "a, &wmarks,
2069 sysfs_scheme->target_nid);
2070 if (!scheme)
2071 return NULL;
2072
2073 err = damos_sysfs_add_quota_score(sysfs_quotas->goals, &scheme->quota);
2074 if (err) {
2075 damon_destroy_scheme(scheme);
2076 return NULL;
2077 }
2078
2079 err = damon_sysfs_add_scheme_filters(scheme, sysfs_filters);
2080 if (err) {
2081 damon_destroy_scheme(scheme);
2082 return NULL;
2083 }
2084 return scheme;
2085}
2086
2087int damon_sysfs_add_schemes(struct damon_ctx *ctx,
2088 struct damon_sysfs_schemes *sysfs_schemes)
2089{
2090 int i;
2091
2092 for (i = 0; i < sysfs_schemes->nr; i++) {
2093 struct damos *scheme, *next;
2094
2095 scheme = damon_sysfs_mk_scheme(sysfs_schemes->schemes_arr[i]);
2096 if (!scheme) {
2097 damon_for_each_scheme_safe(scheme, next, ctx)
2098 damon_destroy_scheme(scheme);
2099 return -ENOMEM;
2100 }
2101 damon_add_scheme(ctx, scheme);
2102 }
2103 return 0;
2104}
2105
2106void damon_sysfs_schemes_update_stats(
2107 struct damon_sysfs_schemes *sysfs_schemes,
2108 struct damon_ctx *ctx)
2109{
2110 struct damos *scheme;
2111 int schemes_idx = 0;
2112
2113 damon_for_each_scheme(scheme, ctx) {
2114 struct damon_sysfs_stats *sysfs_stats;
2115
2116 /* user could have removed the scheme sysfs dir */
2117 if (schemes_idx >= sysfs_schemes->nr)
2118 break;
2119
2120 sysfs_stats = sysfs_schemes->schemes_arr[schemes_idx++]->stats;
2121 sysfs_stats->nr_tried = scheme->stat.nr_tried;
2122 sysfs_stats->sz_tried = scheme->stat.sz_tried;
2123 sysfs_stats->nr_applied = scheme->stat.nr_applied;
2124 sysfs_stats->sz_applied = scheme->stat.sz_applied;
2125 sysfs_stats->qt_exceeds = scheme->stat.qt_exceeds;
2126 }
2127}
2128
2129/*
2130 * damon_sysfs_schemes that need to update its schemes regions dir. Protected
2131 * by damon_sysfs_lock
2132 */
2133static struct damon_sysfs_schemes *damon_sysfs_schemes_for_damos_callback;
2134static int damon_sysfs_schemes_region_idx;
2135static bool damos_regions_upd_total_bytes_only;
2136
2137/*
2138 * DAMON callback that called before damos apply. While this callback is
2139 * registered, damon_sysfs_lock should be held to ensure the regions
2140 * directories exist.
2141 */
2142static int damon_sysfs_before_damos_apply(struct damon_ctx *ctx,
2143 struct damon_target *t, struct damon_region *r,
2144 struct damos *s)
2145{
2146 struct damos *scheme;
2147 struct damon_sysfs_scheme_regions *sysfs_regions;
2148 struct damon_sysfs_scheme_region *region;
2149 struct damon_sysfs_schemes *sysfs_schemes =
2150 damon_sysfs_schemes_for_damos_callback;
2151 int schemes_idx = 0;
2152
2153 damon_for_each_scheme(scheme, ctx) {
2154 if (scheme == s)
2155 break;
2156 schemes_idx++;
2157 }
2158
2159 /* user could have removed the scheme sysfs dir */
2160 if (schemes_idx >= sysfs_schemes->nr)
2161 return 0;
2162
2163 sysfs_regions = sysfs_schemes->schemes_arr[schemes_idx]->tried_regions;
2164 if (sysfs_regions->upd_status == DAMOS_TRIED_REGIONS_UPD_FINISHED)
2165 return 0;
2166 if (sysfs_regions->upd_status == DAMOS_TRIED_REGIONS_UPD_IDLE)
2167 sysfs_regions->upd_status = DAMOS_TRIED_REGIONS_UPD_STARTED;
2168 sysfs_regions->total_bytes += r->ar.end - r->ar.start;
2169 if (damos_regions_upd_total_bytes_only)
2170 return 0;
2171
2172 region = damon_sysfs_scheme_region_alloc(r);
2173 if (!region)
2174 return 0;
2175 list_add_tail(®ion->list, &sysfs_regions->regions_list);
2176 sysfs_regions->nr_regions++;
2177 if (kobject_init_and_add(®ion->kobj,
2178 &damon_sysfs_scheme_region_ktype,
2179 &sysfs_regions->kobj, "%d",
2180 damon_sysfs_schemes_region_idx++)) {
2181 kobject_put(®ion->kobj);
2182 }
2183 return 0;
2184}
2185
2186/*
2187 * DAMON callback that called after each accesses sampling. While this
2188 * callback is registered, damon_sysfs_lock should be held to ensure the
2189 * regions directories exist.
2190 */
2191void damos_sysfs_mark_finished_regions_updates(struct damon_ctx *ctx)
2192{
2193 struct damon_sysfs_schemes *sysfs_schemes =
2194 damon_sysfs_schemes_for_damos_callback;
2195 struct damon_sysfs_scheme_regions *sysfs_regions;
2196 int i;
2197
2198 for (i = 0; i < sysfs_schemes->nr; i++) {
2199 sysfs_regions = sysfs_schemes->schemes_arr[i]->tried_regions;
2200 if (sysfs_regions->upd_status ==
2201 DAMOS_TRIED_REGIONS_UPD_STARTED ||
2202 time_after(jiffies,
2203 sysfs_regions->upd_timeout_jiffies))
2204 sysfs_regions->upd_status =
2205 DAMOS_TRIED_REGIONS_UPD_FINISHED;
2206 }
2207}
2208
2209/* Called from damon_sysfs_cmd_request_callback under damon_sysfs_lock */
2210int damon_sysfs_schemes_clear_regions(
2211 struct damon_sysfs_schemes *sysfs_schemes,
2212 struct damon_ctx *ctx)
2213{
2214 struct damos *scheme;
2215 int schemes_idx = 0;
2216
2217 damon_for_each_scheme(scheme, ctx) {
2218 struct damon_sysfs_scheme *sysfs_scheme;
2219
2220 /* user could have removed the scheme sysfs dir */
2221 if (schemes_idx >= sysfs_schemes->nr)
2222 break;
2223
2224 sysfs_scheme = sysfs_schemes->schemes_arr[schemes_idx++];
2225 damon_sysfs_scheme_regions_rm_dirs(
2226 sysfs_scheme->tried_regions);
2227 sysfs_scheme->tried_regions->total_bytes = 0;
2228 }
2229 return 0;
2230}
2231
2232static struct damos *damos_sysfs_nth_scheme(int n, struct damon_ctx *ctx)
2233{
2234 struct damos *scheme;
2235 int i = 0;
2236
2237 damon_for_each_scheme(scheme, ctx) {
2238 if (i == n)
2239 return scheme;
2240 i++;
2241 }
2242 return NULL;
2243}
2244
2245static void damos_tried_regions_init_upd_status(
2246 struct damon_sysfs_schemes *sysfs_schemes,
2247 struct damon_ctx *ctx)
2248{
2249 int i;
2250 struct damos *scheme;
2251 struct damon_sysfs_scheme_regions *sysfs_regions;
2252
2253 for (i = 0; i < sysfs_schemes->nr; i++) {
2254 sysfs_regions = sysfs_schemes->schemes_arr[i]->tried_regions;
2255 scheme = damos_sysfs_nth_scheme(i, ctx);
2256 if (!scheme) {
2257 sysfs_regions->upd_status =
2258 DAMOS_TRIED_REGIONS_UPD_FINISHED;
2259 continue;
2260 }
2261 sysfs_regions->upd_status = DAMOS_TRIED_REGIONS_UPD_IDLE;
2262 sysfs_regions->upd_timeout_jiffies = jiffies +
2263 2 * usecs_to_jiffies(scheme->apply_interval_us ?
2264 scheme->apply_interval_us :
2265 ctx->attrs.aggr_interval);
2266 }
2267}
2268
2269/* Called from damon_sysfs_cmd_request_callback under damon_sysfs_lock */
2270int damon_sysfs_schemes_update_regions_start(
2271 struct damon_sysfs_schemes *sysfs_schemes,
2272 struct damon_ctx *ctx, bool total_bytes_only)
2273{
2274 damon_sysfs_schemes_clear_regions(sysfs_schemes, ctx);
2275 damon_sysfs_schemes_for_damos_callback = sysfs_schemes;
2276 damos_tried_regions_init_upd_status(sysfs_schemes, ctx);
2277 damos_regions_upd_total_bytes_only = total_bytes_only;
2278 ctx->callback.before_damos_apply = damon_sysfs_before_damos_apply;
2279 return 0;
2280}
2281
2282bool damos_sysfs_regions_upd_done(void)
2283{
2284 struct damon_sysfs_schemes *sysfs_schemes =
2285 damon_sysfs_schemes_for_damos_callback;
2286 struct damon_sysfs_scheme_regions *sysfs_regions;
2287 int i;
2288
2289 for (i = 0; i < sysfs_schemes->nr; i++) {
2290 sysfs_regions = sysfs_schemes->schemes_arr[i]->tried_regions;
2291 if (sysfs_regions->upd_status !=
2292 DAMOS_TRIED_REGIONS_UPD_FINISHED)
2293 return false;
2294 }
2295 return true;
2296}
2297
2298/*
2299 * Called from damon_sysfs_cmd_request_callback under damon_sysfs_lock. Caller
2300 * should unlock damon_sysfs_lock which held before
2301 * damon_sysfs_schemes_update_regions_start()
2302 */
2303int damon_sysfs_schemes_update_regions_stop(struct damon_ctx *ctx)
2304{
2305 damon_sysfs_schemes_for_damos_callback = NULL;
2306 ctx->callback.before_damos_apply = NULL;
2307 damon_sysfs_schemes_region_idx = 0;
2308 return 0;
2309}
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
12/*
13 * scheme region directory
14 */
15
16struct damon_sysfs_scheme_region {
17 struct kobject kobj;
18 struct damon_addr_range ar;
19 unsigned int nr_accesses;
20 unsigned int age;
21 struct list_head list;
22};
23
24static struct damon_sysfs_scheme_region *damon_sysfs_scheme_region_alloc(
25 struct damon_region *region)
26{
27 struct damon_sysfs_scheme_region *sysfs_region = kmalloc(
28 sizeof(*sysfs_region), GFP_KERNEL);
29
30 if (!sysfs_region)
31 return NULL;
32 sysfs_region->kobj = (struct kobject){};
33 sysfs_region->ar = region->ar;
34 sysfs_region->nr_accesses = region->nr_accesses_bp / 10000;
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(®ion->list);
82 kfree(region);
83}
84
85static struct kobj_attribute damon_sysfs_scheme_region_start_attr =
86 __ATTR_RO_MODE(start, 0400);
87
88static struct kobj_attribute damon_sysfs_scheme_region_end_attr =
89 __ATTR_RO_MODE(end, 0400);
90
91static struct kobj_attribute damon_sysfs_scheme_region_nr_accesses_attr =
92 __ATTR_RO_MODE(nr_accesses, 0400);
93
94static struct kobj_attribute damon_sysfs_scheme_region_age_attr =
95 __ATTR_RO_MODE(age, 0400);
96
97static struct attribute *damon_sysfs_scheme_region_attrs[] = {
98 &damon_sysfs_scheme_region_start_attr.attr,
99 &damon_sysfs_scheme_region_end_attr.attr,
100 &damon_sysfs_scheme_region_nr_accesses_attr.attr,
101 &damon_sysfs_scheme_region_age_attr.attr,
102 NULL,
103};
104ATTRIBUTE_GROUPS(damon_sysfs_scheme_region);
105
106static const struct kobj_type damon_sysfs_scheme_region_ktype = {
107 .release = damon_sysfs_scheme_region_release,
108 .sysfs_ops = &kobj_sysfs_ops,
109 .default_groups = damon_sysfs_scheme_region_groups,
110};
111
112/*
113 * scheme regions directory
114 */
115
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()
131 * callback.
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() or ->after_aggregation() callback
136 * (damon_sysfs_cmd_request_callback()) after the call is called only after
137 * the scheme is completely applied to the given snapshot. Hence the callback
138 * knows the situation by showing 'started' status, and sets the status as
139 * 'finished'. Then, damon_sysfs_before_damos_apply() understands the
140 * situation by showing the 'finished' status and do nothing.
141 *
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 *
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
158struct damon_sysfs_scheme_regions {
159 struct kobject kobj;
160 struct list_head regions_list;
161 int nr_regions;
162 unsigned long total_bytes;
163 enum damos_sysfs_regions_upd_status upd_status;
164 unsigned long upd_timeout_jiffies;
165};
166
167static struct damon_sysfs_scheme_regions *
168damon_sysfs_scheme_regions_alloc(void)
169{
170 struct damon_sysfs_scheme_regions *regions = kmalloc(sizeof(*regions),
171 GFP_KERNEL);
172
173 if (!regions)
174 return NULL;
175
176 regions->kobj = (struct kobject){};
177 INIT_LIST_HEAD(®ions->regions_list);
178 regions->nr_regions = 0;
179 regions->total_bytes = 0;
180 regions->upd_status = DAMOS_TRIED_REGIONS_UPD_IDLE;
181 return regions;
182}
183
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
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, ®ions->regions_list, list) {
199 /* release function deletes it from the list */
200 kobject_put(&r->kobj);
201 regions->nr_regions--;
202 }
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
210static struct kobj_attribute damon_sysfs_scheme_regions_total_bytes_attr =
211 __ATTR_RO_MODE(total_bytes, 0400);
212
213static struct attribute *damon_sysfs_scheme_regions_attrs[] = {
214 &damon_sysfs_scheme_regions_total_bytes_attr.attr,
215 NULL,
216};
217ATTRIBUTE_GROUPS(damon_sysfs_scheme_regions);
218
219static const struct kobj_type damon_sysfs_scheme_regions_ktype = {
220 .release = damon_sysfs_scheme_regions_release,
221 .sysfs_ops = &kobj_sysfs_ops,
222 .default_groups = damon_sysfs_scheme_regions_groups,
223};
224
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
318static const struct kobj_type damon_sysfs_stats_ktype = {
319 .release = damon_sysfs_stats_release,
320 .sysfs_ops = &kobj_sysfs_ops,
321 .default_groups = damon_sysfs_stats_groups,
322};
323
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;
333 struct damon_addr_range addr_range;
334 int target_idx;
335};
336
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
342/* Should match with enum damos_filter_type */
343static const char * const damon_sysfs_scheme_filter_type_strs[] = {
344 "anon",
345 "memcg",
346 "addr",
347 "target",
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
423 strscpy(path, buf, count + 1);
424 filter->memcg_path = path;
425 return count;
426}
427
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
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
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
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
509static struct kobj_attribute damon_sysfs_scheme_filter_damon_target_idx_attr =
510 __ATTR_RW_MODE(damon_target_idx, 0600);
511
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,
516 &damon_sysfs_scheme_filter_addr_start_attr.attr,
517 &damon_sysfs_scheme_filter_addr_end_attr.attr,
518 &damon_sysfs_scheme_filter_damon_target_idx_attr.attr,
519 NULL,
520};
521ATTRIBUTE_GROUPS(damon_sysfs_scheme_filter);
522
523static const struct kobj_type damon_sysfs_scheme_filter_ktype = {
524 .release = damon_sysfs_scheme_filter_release,
525 .sysfs_ops = &kobj_sysfs_ops,
526 .default_groups = damon_sysfs_scheme_filter_groups,
527};
528
529/*
530 * filters directory
531 */
532
533struct damon_sysfs_scheme_filters {
534 struct kobject kobj;
535 struct damon_sysfs_scheme_filter **filters_arr;
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
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
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{
608 struct damon_sysfs_scheme_filters *filters;
609 int nr, err = kstrtoint(buf, 0, &nr);
610
611 if (err)
612 return err;
613 if (nr < 0)
614 return -EINVAL;
615
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
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
642static const struct kobj_type damon_sysfs_scheme_filters_ktype = {
643 .release = damon_sysfs_scheme_filters_release,
644 .sysfs_ops = &kobj_sysfs_ops,
645 .default_groups = damon_sysfs_scheme_filters_groups,
646};
647
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
817static const struct kobj_type damon_sysfs_watermarks_ktype = {
818 .release = damon_sysfs_watermarks_release,
819 .sysfs_ops = &kobj_sysfs_ops,
820 .default_groups = damon_sysfs_watermarks_groups,
821};
822
823/*
824 * quota goal directory
825 */
826
827struct damos_sysfs_quota_goal {
828 struct kobject kobj;
829 enum damos_quota_goal_metric metric;
830 unsigned long target_value;
831 unsigned long current_value;
832};
833
834/* This should match with enum damos_action */
835static const char * const damos_sysfs_quota_goal_metric_strs[] = {
836 "user_input",
837 "some_mem_psi_us",
838};
839
840static struct damos_sysfs_quota_goal *damos_sysfs_quota_goal_alloc(void)
841{
842 return kzalloc(sizeof(struct damos_sysfs_quota_goal), GFP_KERNEL);
843}
844
845static ssize_t target_metric_show(struct kobject *kobj,
846 struct kobj_attribute *attr, char *buf)
847{
848 struct damos_sysfs_quota_goal *goal = container_of(kobj,
849 struct damos_sysfs_quota_goal, kobj);
850
851 return sysfs_emit(buf, "%s\n",
852 damos_sysfs_quota_goal_metric_strs[goal->metric]);
853}
854
855static ssize_t target_metric_store(struct kobject *kobj,
856 struct kobj_attribute *attr, const char *buf, size_t count)
857{
858 struct damos_sysfs_quota_goal *goal = container_of(kobj,
859 struct damos_sysfs_quota_goal, kobj);
860 enum damos_quota_goal_metric m;
861
862 for (m = 0; m < NR_DAMOS_QUOTA_GOAL_METRICS; m++) {
863 if (sysfs_streq(buf, damos_sysfs_quota_goal_metric_strs[m])) {
864 goal->metric = m;
865 return count;
866 }
867 }
868 return -EINVAL;
869}
870
871static ssize_t target_value_show(struct kobject *kobj,
872 struct kobj_attribute *attr, char *buf)
873{
874 struct damos_sysfs_quota_goal *goal = container_of(kobj, struct
875 damos_sysfs_quota_goal, kobj);
876
877 return sysfs_emit(buf, "%lu\n", goal->target_value);
878}
879
880static ssize_t target_value_store(struct kobject *kobj,
881 struct kobj_attribute *attr, const char *buf, size_t count)
882{
883 struct damos_sysfs_quota_goal *goal = container_of(kobj, struct
884 damos_sysfs_quota_goal, kobj);
885 int err = kstrtoul(buf, 0, &goal->target_value);
886
887 return err ? err : count;
888}
889
890static ssize_t current_value_show(struct kobject *kobj,
891 struct kobj_attribute *attr, char *buf)
892{
893 struct damos_sysfs_quota_goal *goal = container_of(kobj, struct
894 damos_sysfs_quota_goal, kobj);
895
896 return sysfs_emit(buf, "%lu\n", goal->current_value);
897}
898
899static ssize_t current_value_store(struct kobject *kobj,
900 struct kobj_attribute *attr, const char *buf, size_t count)
901{
902 struct damos_sysfs_quota_goal *goal = container_of(kobj, struct
903 damos_sysfs_quota_goal, kobj);
904 int err = kstrtoul(buf, 0, &goal->current_value);
905
906 /* feed callback should check existence of this file and read value */
907 return err ? err : count;
908}
909
910static void damos_sysfs_quota_goal_release(struct kobject *kobj)
911{
912 /* or, notify this release to the feed callback */
913 kfree(container_of(kobj, struct damos_sysfs_quota_goal, kobj));
914}
915
916static struct kobj_attribute damos_sysfs_quota_goal_target_metric_attr =
917 __ATTR_RW_MODE(target_metric, 0600);
918
919static struct kobj_attribute damos_sysfs_quota_goal_target_value_attr =
920 __ATTR_RW_MODE(target_value, 0600);
921
922static struct kobj_attribute damos_sysfs_quota_goal_current_value_attr =
923 __ATTR_RW_MODE(current_value, 0600);
924
925static struct attribute *damos_sysfs_quota_goal_attrs[] = {
926 &damos_sysfs_quota_goal_target_metric_attr.attr,
927 &damos_sysfs_quota_goal_target_value_attr.attr,
928 &damos_sysfs_quota_goal_current_value_attr.attr,
929 NULL,
930};
931ATTRIBUTE_GROUPS(damos_sysfs_quota_goal);
932
933static const struct kobj_type damos_sysfs_quota_goal_ktype = {
934 .release = damos_sysfs_quota_goal_release,
935 .sysfs_ops = &kobj_sysfs_ops,
936 .default_groups = damos_sysfs_quota_goal_groups,
937};
938
939/*
940 * quota goals directory
941 */
942
943struct damos_sysfs_quota_goals {
944 struct kobject kobj;
945 struct damos_sysfs_quota_goal **goals_arr; /* counted by nr */
946 int nr;
947};
948
949static struct damos_sysfs_quota_goals *damos_sysfs_quota_goals_alloc(void)
950{
951 return kzalloc(sizeof(struct damos_sysfs_quota_goals), GFP_KERNEL);
952}
953
954static void damos_sysfs_quota_goals_rm_dirs(
955 struct damos_sysfs_quota_goals *goals)
956{
957 struct damos_sysfs_quota_goal **goals_arr = goals->goals_arr;
958 int i;
959
960 for (i = 0; i < goals->nr; i++)
961 kobject_put(&goals_arr[i]->kobj);
962 goals->nr = 0;
963 kfree(goals_arr);
964 goals->goals_arr = NULL;
965}
966
967static int damos_sysfs_quota_goals_add_dirs(
968 struct damos_sysfs_quota_goals *goals, int nr_goals)
969{
970 struct damos_sysfs_quota_goal **goals_arr, *goal;
971 int err, i;
972
973 damos_sysfs_quota_goals_rm_dirs(goals);
974 if (!nr_goals)
975 return 0;
976
977 goals_arr = kmalloc_array(nr_goals, sizeof(*goals_arr),
978 GFP_KERNEL | __GFP_NOWARN);
979 if (!goals_arr)
980 return -ENOMEM;
981 goals->goals_arr = goals_arr;
982
983 for (i = 0; i < nr_goals; i++) {
984 goal = damos_sysfs_quota_goal_alloc();
985 if (!goal) {
986 damos_sysfs_quota_goals_rm_dirs(goals);
987 return -ENOMEM;
988 }
989
990 err = kobject_init_and_add(&goal->kobj,
991 &damos_sysfs_quota_goal_ktype, &goals->kobj,
992 "%d", i);
993 if (err) {
994 kobject_put(&goal->kobj);
995 damos_sysfs_quota_goals_rm_dirs(goals);
996 return err;
997 }
998
999 goals_arr[i] = goal;
1000 goals->nr++;
1001 }
1002 return 0;
1003}
1004
1005static ssize_t nr_goals_show(struct kobject *kobj,
1006 struct kobj_attribute *attr, char *buf)
1007{
1008 struct damos_sysfs_quota_goals *goals = container_of(kobj,
1009 struct damos_sysfs_quota_goals, kobj);
1010
1011 return sysfs_emit(buf, "%d\n", goals->nr);
1012}
1013
1014static ssize_t nr_goals_store(struct kobject *kobj,
1015 struct kobj_attribute *attr, const char *buf, size_t count)
1016{
1017 struct damos_sysfs_quota_goals *goals;
1018 int nr, err = kstrtoint(buf, 0, &nr);
1019
1020 if (err)
1021 return err;
1022 if (nr < 0)
1023 return -EINVAL;
1024
1025 goals = container_of(kobj, struct damos_sysfs_quota_goals, kobj);
1026
1027 if (!mutex_trylock(&damon_sysfs_lock))
1028 return -EBUSY;
1029 err = damos_sysfs_quota_goals_add_dirs(goals, nr);
1030 mutex_unlock(&damon_sysfs_lock);
1031 if (err)
1032 return err;
1033
1034 return count;
1035}
1036
1037static void damos_sysfs_quota_goals_release(struct kobject *kobj)
1038{
1039 kfree(container_of(kobj, struct damos_sysfs_quota_goals, kobj));
1040}
1041
1042static struct kobj_attribute damos_sysfs_quota_goals_nr_attr =
1043 __ATTR_RW_MODE(nr_goals, 0600);
1044
1045static struct attribute *damos_sysfs_quota_goals_attrs[] = {
1046 &damos_sysfs_quota_goals_nr_attr.attr,
1047 NULL,
1048};
1049ATTRIBUTE_GROUPS(damos_sysfs_quota_goals);
1050
1051static const struct kobj_type damos_sysfs_quota_goals_ktype = {
1052 .release = damos_sysfs_quota_goals_release,
1053 .sysfs_ops = &kobj_sysfs_ops,
1054 .default_groups = damos_sysfs_quota_goals_groups,
1055};
1056
1057/*
1058 * scheme/weights directory
1059 */
1060
1061struct damon_sysfs_weights {
1062 struct kobject kobj;
1063 unsigned int sz;
1064 unsigned int nr_accesses;
1065 unsigned int age;
1066};
1067
1068static struct damon_sysfs_weights *damon_sysfs_weights_alloc(unsigned int sz,
1069 unsigned int nr_accesses, unsigned int age)
1070{
1071 struct damon_sysfs_weights *weights = kmalloc(sizeof(*weights),
1072 GFP_KERNEL);
1073
1074 if (!weights)
1075 return NULL;
1076 weights->kobj = (struct kobject){};
1077 weights->sz = sz;
1078 weights->nr_accesses = nr_accesses;
1079 weights->age = age;
1080 return weights;
1081}
1082
1083static ssize_t sz_permil_show(struct kobject *kobj,
1084 struct kobj_attribute *attr, char *buf)
1085{
1086 struct damon_sysfs_weights *weights = container_of(kobj,
1087 struct damon_sysfs_weights, kobj);
1088
1089 return sysfs_emit(buf, "%u\n", weights->sz);
1090}
1091
1092static ssize_t sz_permil_store(struct kobject *kobj,
1093 struct kobj_attribute *attr, const char *buf, size_t count)
1094{
1095 struct damon_sysfs_weights *weights = container_of(kobj,
1096 struct damon_sysfs_weights, kobj);
1097 int err = kstrtouint(buf, 0, &weights->sz);
1098
1099 return err ? err : count;
1100}
1101
1102static ssize_t nr_accesses_permil_show(struct kobject *kobj,
1103 struct kobj_attribute *attr, char *buf)
1104{
1105 struct damon_sysfs_weights *weights = container_of(kobj,
1106 struct damon_sysfs_weights, kobj);
1107
1108 return sysfs_emit(buf, "%u\n", weights->nr_accesses);
1109}
1110
1111static ssize_t nr_accesses_permil_store(struct kobject *kobj,
1112 struct kobj_attribute *attr, const char *buf, size_t count)
1113{
1114 struct damon_sysfs_weights *weights = container_of(kobj,
1115 struct damon_sysfs_weights, kobj);
1116 int err = kstrtouint(buf, 0, &weights->nr_accesses);
1117
1118 return err ? err : count;
1119}
1120
1121static ssize_t age_permil_show(struct kobject *kobj,
1122 struct kobj_attribute *attr, char *buf)
1123{
1124 struct damon_sysfs_weights *weights = container_of(kobj,
1125 struct damon_sysfs_weights, kobj);
1126
1127 return sysfs_emit(buf, "%u\n", weights->age);
1128}
1129
1130static ssize_t age_permil_store(struct kobject *kobj,
1131 struct kobj_attribute *attr, const char *buf, size_t count)
1132{
1133 struct damon_sysfs_weights *weights = container_of(kobj,
1134 struct damon_sysfs_weights, kobj);
1135 int err = kstrtouint(buf, 0, &weights->age);
1136
1137 return err ? err : count;
1138}
1139
1140static void damon_sysfs_weights_release(struct kobject *kobj)
1141{
1142 kfree(container_of(kobj, struct damon_sysfs_weights, kobj));
1143}
1144
1145static struct kobj_attribute damon_sysfs_weights_sz_attr =
1146 __ATTR_RW_MODE(sz_permil, 0600);
1147
1148static struct kobj_attribute damon_sysfs_weights_nr_accesses_attr =
1149 __ATTR_RW_MODE(nr_accesses_permil, 0600);
1150
1151static struct kobj_attribute damon_sysfs_weights_age_attr =
1152 __ATTR_RW_MODE(age_permil, 0600);
1153
1154static struct attribute *damon_sysfs_weights_attrs[] = {
1155 &damon_sysfs_weights_sz_attr.attr,
1156 &damon_sysfs_weights_nr_accesses_attr.attr,
1157 &damon_sysfs_weights_age_attr.attr,
1158 NULL,
1159};
1160ATTRIBUTE_GROUPS(damon_sysfs_weights);
1161
1162static const struct kobj_type damon_sysfs_weights_ktype = {
1163 .release = damon_sysfs_weights_release,
1164 .sysfs_ops = &kobj_sysfs_ops,
1165 .default_groups = damon_sysfs_weights_groups,
1166};
1167
1168/*
1169 * quotas directory
1170 */
1171
1172struct damon_sysfs_quotas {
1173 struct kobject kobj;
1174 struct damon_sysfs_weights *weights;
1175 struct damos_sysfs_quota_goals *goals;
1176 unsigned long ms;
1177 unsigned long sz;
1178 unsigned long reset_interval_ms;
1179 unsigned long effective_sz; /* Effective size quota in bytes */
1180};
1181
1182static struct damon_sysfs_quotas *damon_sysfs_quotas_alloc(void)
1183{
1184 return kzalloc(sizeof(struct damon_sysfs_quotas), GFP_KERNEL);
1185}
1186
1187static int damon_sysfs_quotas_add_dirs(struct damon_sysfs_quotas *quotas)
1188{
1189 struct damon_sysfs_weights *weights;
1190 struct damos_sysfs_quota_goals *goals;
1191 int err;
1192
1193 weights = damon_sysfs_weights_alloc(0, 0, 0);
1194 if (!weights)
1195 return -ENOMEM;
1196
1197 err = kobject_init_and_add(&weights->kobj, &damon_sysfs_weights_ktype,
1198 "as->kobj, "weights");
1199 if (err) {
1200 kobject_put(&weights->kobj);
1201 return err;
1202 }
1203 quotas->weights = weights;
1204
1205 goals = damos_sysfs_quota_goals_alloc();
1206 if (!goals) {
1207 kobject_put(&weights->kobj);
1208 return -ENOMEM;
1209 }
1210 err = kobject_init_and_add(&goals->kobj,
1211 &damos_sysfs_quota_goals_ktype, "as->kobj,
1212 "goals");
1213 if (err) {
1214 kobject_put(&weights->kobj);
1215 kobject_put(&goals->kobj);
1216 } else {
1217 quotas->goals = goals;
1218 }
1219
1220 return err;
1221}
1222
1223static void damon_sysfs_quotas_rm_dirs(struct damon_sysfs_quotas *quotas)
1224{
1225 kobject_put("as->weights->kobj);
1226 damos_sysfs_quota_goals_rm_dirs(quotas->goals);
1227 kobject_put("as->goals->kobj);
1228}
1229
1230static ssize_t ms_show(struct kobject *kobj, struct kobj_attribute *attr,
1231 char *buf)
1232{
1233 struct damon_sysfs_quotas *quotas = container_of(kobj,
1234 struct damon_sysfs_quotas, kobj);
1235
1236 return sysfs_emit(buf, "%lu\n", quotas->ms);
1237}
1238
1239static ssize_t ms_store(struct kobject *kobj, struct kobj_attribute *attr,
1240 const char *buf, size_t count)
1241{
1242 struct damon_sysfs_quotas *quotas = container_of(kobj,
1243 struct damon_sysfs_quotas, kobj);
1244 int err = kstrtoul(buf, 0, "as->ms);
1245
1246 if (err)
1247 return -EINVAL;
1248 return count;
1249}
1250
1251static ssize_t bytes_show(struct kobject *kobj, struct kobj_attribute *attr,
1252 char *buf)
1253{
1254 struct damon_sysfs_quotas *quotas = container_of(kobj,
1255 struct damon_sysfs_quotas, kobj);
1256
1257 return sysfs_emit(buf, "%lu\n", quotas->sz);
1258}
1259
1260static ssize_t bytes_store(struct kobject *kobj,
1261 struct kobj_attribute *attr, const char *buf, size_t count)
1262{
1263 struct damon_sysfs_quotas *quotas = container_of(kobj,
1264 struct damon_sysfs_quotas, kobj);
1265 int err = kstrtoul(buf, 0, "as->sz);
1266
1267 if (err)
1268 return -EINVAL;
1269 return count;
1270}
1271
1272static ssize_t reset_interval_ms_show(struct kobject *kobj,
1273 struct kobj_attribute *attr, char *buf)
1274{
1275 struct damon_sysfs_quotas *quotas = container_of(kobj,
1276 struct damon_sysfs_quotas, kobj);
1277
1278 return sysfs_emit(buf, "%lu\n", quotas->reset_interval_ms);
1279}
1280
1281static ssize_t reset_interval_ms_store(struct kobject *kobj,
1282 struct kobj_attribute *attr, const char *buf, size_t count)
1283{
1284 struct damon_sysfs_quotas *quotas = container_of(kobj,
1285 struct damon_sysfs_quotas, kobj);
1286 int err = kstrtoul(buf, 0, "as->reset_interval_ms);
1287
1288 if (err)
1289 return -EINVAL;
1290 return count;
1291}
1292
1293static ssize_t effective_bytes_show(struct kobject *kobj,
1294 struct kobj_attribute *attr, char *buf)
1295{
1296 struct damon_sysfs_quotas *quotas = container_of(kobj,
1297 struct damon_sysfs_quotas, kobj);
1298
1299 return sysfs_emit(buf, "%lu\n", quotas->effective_sz);
1300}
1301
1302static void damon_sysfs_quotas_release(struct kobject *kobj)
1303{
1304 kfree(container_of(kobj, struct damon_sysfs_quotas, kobj));
1305}
1306
1307static struct kobj_attribute damon_sysfs_quotas_ms_attr =
1308 __ATTR_RW_MODE(ms, 0600);
1309
1310static struct kobj_attribute damon_sysfs_quotas_sz_attr =
1311 __ATTR_RW_MODE(bytes, 0600);
1312
1313static struct kobj_attribute damon_sysfs_quotas_reset_interval_ms_attr =
1314 __ATTR_RW_MODE(reset_interval_ms, 0600);
1315
1316static struct kobj_attribute damon_sysfs_quotas_effective_bytes_attr =
1317 __ATTR_RO_MODE(effective_bytes, 0400);
1318
1319static struct attribute *damon_sysfs_quotas_attrs[] = {
1320 &damon_sysfs_quotas_ms_attr.attr,
1321 &damon_sysfs_quotas_sz_attr.attr,
1322 &damon_sysfs_quotas_reset_interval_ms_attr.attr,
1323 &damon_sysfs_quotas_effective_bytes_attr.attr,
1324 NULL,
1325};
1326ATTRIBUTE_GROUPS(damon_sysfs_quotas);
1327
1328static const struct kobj_type damon_sysfs_quotas_ktype = {
1329 .release = damon_sysfs_quotas_release,
1330 .sysfs_ops = &kobj_sysfs_ops,
1331 .default_groups = damon_sysfs_quotas_groups,
1332};
1333
1334/*
1335 * access_pattern directory
1336 */
1337
1338struct damon_sysfs_access_pattern {
1339 struct kobject kobj;
1340 struct damon_sysfs_ul_range *sz;
1341 struct damon_sysfs_ul_range *nr_accesses;
1342 struct damon_sysfs_ul_range *age;
1343};
1344
1345static
1346struct damon_sysfs_access_pattern *damon_sysfs_access_pattern_alloc(void)
1347{
1348 struct damon_sysfs_access_pattern *access_pattern =
1349 kmalloc(sizeof(*access_pattern), GFP_KERNEL);
1350
1351 if (!access_pattern)
1352 return NULL;
1353 access_pattern->kobj = (struct kobject){};
1354 return access_pattern;
1355}
1356
1357static int damon_sysfs_access_pattern_add_range_dir(
1358 struct damon_sysfs_access_pattern *access_pattern,
1359 struct damon_sysfs_ul_range **range_dir_ptr,
1360 char *name)
1361{
1362 struct damon_sysfs_ul_range *range = damon_sysfs_ul_range_alloc(0, 0);
1363 int err;
1364
1365 if (!range)
1366 return -ENOMEM;
1367 err = kobject_init_and_add(&range->kobj, &damon_sysfs_ul_range_ktype,
1368 &access_pattern->kobj, name);
1369 if (err)
1370 kobject_put(&range->kobj);
1371 else
1372 *range_dir_ptr = range;
1373 return err;
1374}
1375
1376static int damon_sysfs_access_pattern_add_dirs(
1377 struct damon_sysfs_access_pattern *access_pattern)
1378{
1379 int err;
1380
1381 err = damon_sysfs_access_pattern_add_range_dir(access_pattern,
1382 &access_pattern->sz, "sz");
1383 if (err)
1384 goto put_sz_out;
1385
1386 err = damon_sysfs_access_pattern_add_range_dir(access_pattern,
1387 &access_pattern->nr_accesses, "nr_accesses");
1388 if (err)
1389 goto put_nr_accesses_sz_out;
1390
1391 err = damon_sysfs_access_pattern_add_range_dir(access_pattern,
1392 &access_pattern->age, "age");
1393 if (err)
1394 goto put_age_nr_accesses_sz_out;
1395 return 0;
1396
1397put_age_nr_accesses_sz_out:
1398 kobject_put(&access_pattern->age->kobj);
1399 access_pattern->age = NULL;
1400put_nr_accesses_sz_out:
1401 kobject_put(&access_pattern->nr_accesses->kobj);
1402 access_pattern->nr_accesses = NULL;
1403put_sz_out:
1404 kobject_put(&access_pattern->sz->kobj);
1405 access_pattern->sz = NULL;
1406 return err;
1407}
1408
1409static void damon_sysfs_access_pattern_rm_dirs(
1410 struct damon_sysfs_access_pattern *access_pattern)
1411{
1412 kobject_put(&access_pattern->sz->kobj);
1413 kobject_put(&access_pattern->nr_accesses->kobj);
1414 kobject_put(&access_pattern->age->kobj);
1415}
1416
1417static void damon_sysfs_access_pattern_release(struct kobject *kobj)
1418{
1419 kfree(container_of(kobj, struct damon_sysfs_access_pattern, kobj));
1420}
1421
1422static struct attribute *damon_sysfs_access_pattern_attrs[] = {
1423 NULL,
1424};
1425ATTRIBUTE_GROUPS(damon_sysfs_access_pattern);
1426
1427static const struct kobj_type damon_sysfs_access_pattern_ktype = {
1428 .release = damon_sysfs_access_pattern_release,
1429 .sysfs_ops = &kobj_sysfs_ops,
1430 .default_groups = damon_sysfs_access_pattern_groups,
1431};
1432
1433/*
1434 * scheme directory
1435 */
1436
1437struct damon_sysfs_scheme {
1438 struct kobject kobj;
1439 enum damos_action action;
1440 struct damon_sysfs_access_pattern *access_pattern;
1441 unsigned long apply_interval_us;
1442 struct damon_sysfs_quotas *quotas;
1443 struct damon_sysfs_watermarks *watermarks;
1444 struct damon_sysfs_scheme_filters *filters;
1445 struct damon_sysfs_stats *stats;
1446 struct damon_sysfs_scheme_regions *tried_regions;
1447};
1448
1449/* This should match with enum damos_action */
1450static const char * const damon_sysfs_damos_action_strs[] = {
1451 "willneed",
1452 "cold",
1453 "pageout",
1454 "hugepage",
1455 "nohugepage",
1456 "lru_prio",
1457 "lru_deprio",
1458 "stat",
1459};
1460
1461static struct damon_sysfs_scheme *damon_sysfs_scheme_alloc(
1462 enum damos_action action, unsigned long apply_interval_us)
1463{
1464 struct damon_sysfs_scheme *scheme = kmalloc(sizeof(*scheme),
1465 GFP_KERNEL);
1466
1467 if (!scheme)
1468 return NULL;
1469 scheme->kobj = (struct kobject){};
1470 scheme->action = action;
1471 scheme->apply_interval_us = apply_interval_us;
1472 return scheme;
1473}
1474
1475static int damon_sysfs_scheme_set_access_pattern(
1476 struct damon_sysfs_scheme *scheme)
1477{
1478 struct damon_sysfs_access_pattern *access_pattern;
1479 int err;
1480
1481 access_pattern = damon_sysfs_access_pattern_alloc();
1482 if (!access_pattern)
1483 return -ENOMEM;
1484 err = kobject_init_and_add(&access_pattern->kobj,
1485 &damon_sysfs_access_pattern_ktype, &scheme->kobj,
1486 "access_pattern");
1487 if (err)
1488 goto out;
1489 err = damon_sysfs_access_pattern_add_dirs(access_pattern);
1490 if (err)
1491 goto out;
1492 scheme->access_pattern = access_pattern;
1493 return 0;
1494
1495out:
1496 kobject_put(&access_pattern->kobj);
1497 return err;
1498}
1499
1500static int damon_sysfs_scheme_set_quotas(struct damon_sysfs_scheme *scheme)
1501{
1502 struct damon_sysfs_quotas *quotas = damon_sysfs_quotas_alloc();
1503 int err;
1504
1505 if (!quotas)
1506 return -ENOMEM;
1507 err = kobject_init_and_add("as->kobj, &damon_sysfs_quotas_ktype,
1508 &scheme->kobj, "quotas");
1509 if (err)
1510 goto out;
1511 err = damon_sysfs_quotas_add_dirs(quotas);
1512 if (err)
1513 goto out;
1514 scheme->quotas = quotas;
1515 return 0;
1516
1517out:
1518 kobject_put("as->kobj);
1519 return err;
1520}
1521
1522static int damon_sysfs_scheme_set_watermarks(struct damon_sysfs_scheme *scheme)
1523{
1524 struct damon_sysfs_watermarks *watermarks =
1525 damon_sysfs_watermarks_alloc(DAMOS_WMARK_NONE, 0, 0, 0, 0);
1526 int err;
1527
1528 if (!watermarks)
1529 return -ENOMEM;
1530 err = kobject_init_and_add(&watermarks->kobj,
1531 &damon_sysfs_watermarks_ktype, &scheme->kobj,
1532 "watermarks");
1533 if (err)
1534 kobject_put(&watermarks->kobj);
1535 else
1536 scheme->watermarks = watermarks;
1537 return err;
1538}
1539
1540static int damon_sysfs_scheme_set_filters(struct damon_sysfs_scheme *scheme)
1541{
1542 struct damon_sysfs_scheme_filters *filters =
1543 damon_sysfs_scheme_filters_alloc();
1544 int err;
1545
1546 if (!filters)
1547 return -ENOMEM;
1548 err = kobject_init_and_add(&filters->kobj,
1549 &damon_sysfs_scheme_filters_ktype, &scheme->kobj,
1550 "filters");
1551 if (err)
1552 kobject_put(&filters->kobj);
1553 else
1554 scheme->filters = filters;
1555 return err;
1556}
1557
1558static int damon_sysfs_scheme_set_stats(struct damon_sysfs_scheme *scheme)
1559{
1560 struct damon_sysfs_stats *stats = damon_sysfs_stats_alloc();
1561 int err;
1562
1563 if (!stats)
1564 return -ENOMEM;
1565 err = kobject_init_and_add(&stats->kobj, &damon_sysfs_stats_ktype,
1566 &scheme->kobj, "stats");
1567 if (err)
1568 kobject_put(&stats->kobj);
1569 else
1570 scheme->stats = stats;
1571 return err;
1572}
1573
1574static int damon_sysfs_scheme_set_tried_regions(
1575 struct damon_sysfs_scheme *scheme)
1576{
1577 struct damon_sysfs_scheme_regions *tried_regions =
1578 damon_sysfs_scheme_regions_alloc();
1579 int err;
1580
1581 if (!tried_regions)
1582 return -ENOMEM;
1583 err = kobject_init_and_add(&tried_regions->kobj,
1584 &damon_sysfs_scheme_regions_ktype, &scheme->kobj,
1585 "tried_regions");
1586 if (err)
1587 kobject_put(&tried_regions->kobj);
1588 else
1589 scheme->tried_regions = tried_regions;
1590 return err;
1591}
1592
1593static int damon_sysfs_scheme_add_dirs(struct damon_sysfs_scheme *scheme)
1594{
1595 int err;
1596
1597 err = damon_sysfs_scheme_set_access_pattern(scheme);
1598 if (err)
1599 return err;
1600 err = damon_sysfs_scheme_set_quotas(scheme);
1601 if (err)
1602 goto put_access_pattern_out;
1603 err = damon_sysfs_scheme_set_watermarks(scheme);
1604 if (err)
1605 goto put_quotas_access_pattern_out;
1606 err = damon_sysfs_scheme_set_filters(scheme);
1607 if (err)
1608 goto put_watermarks_quotas_access_pattern_out;
1609 err = damon_sysfs_scheme_set_stats(scheme);
1610 if (err)
1611 goto put_filters_watermarks_quotas_access_pattern_out;
1612 err = damon_sysfs_scheme_set_tried_regions(scheme);
1613 if (err)
1614 goto put_tried_regions_out;
1615 return 0;
1616
1617put_tried_regions_out:
1618 kobject_put(&scheme->tried_regions->kobj);
1619 scheme->tried_regions = NULL;
1620put_filters_watermarks_quotas_access_pattern_out:
1621 kobject_put(&scheme->filters->kobj);
1622 scheme->filters = NULL;
1623put_watermarks_quotas_access_pattern_out:
1624 kobject_put(&scheme->watermarks->kobj);
1625 scheme->watermarks = NULL;
1626put_quotas_access_pattern_out:
1627 kobject_put(&scheme->quotas->kobj);
1628 scheme->quotas = NULL;
1629put_access_pattern_out:
1630 kobject_put(&scheme->access_pattern->kobj);
1631 scheme->access_pattern = NULL;
1632 return err;
1633}
1634
1635static void damon_sysfs_scheme_rm_dirs(struct damon_sysfs_scheme *scheme)
1636{
1637 damon_sysfs_access_pattern_rm_dirs(scheme->access_pattern);
1638 kobject_put(&scheme->access_pattern->kobj);
1639 damon_sysfs_quotas_rm_dirs(scheme->quotas);
1640 kobject_put(&scheme->quotas->kobj);
1641 kobject_put(&scheme->watermarks->kobj);
1642 damon_sysfs_scheme_filters_rm_dirs(scheme->filters);
1643 kobject_put(&scheme->filters->kobj);
1644 kobject_put(&scheme->stats->kobj);
1645 damon_sysfs_scheme_regions_rm_dirs(scheme->tried_regions);
1646 kobject_put(&scheme->tried_regions->kobj);
1647}
1648
1649static ssize_t action_show(struct kobject *kobj, struct kobj_attribute *attr,
1650 char *buf)
1651{
1652 struct damon_sysfs_scheme *scheme = container_of(kobj,
1653 struct damon_sysfs_scheme, kobj);
1654
1655 return sysfs_emit(buf, "%s\n",
1656 damon_sysfs_damos_action_strs[scheme->action]);
1657}
1658
1659static ssize_t action_store(struct kobject *kobj, struct kobj_attribute *attr,
1660 const char *buf, size_t count)
1661{
1662 struct damon_sysfs_scheme *scheme = container_of(kobj,
1663 struct damon_sysfs_scheme, kobj);
1664 enum damos_action action;
1665
1666 for (action = 0; action < NR_DAMOS_ACTIONS; action++) {
1667 if (sysfs_streq(buf, damon_sysfs_damos_action_strs[action])) {
1668 scheme->action = action;
1669 return count;
1670 }
1671 }
1672 return -EINVAL;
1673}
1674
1675static ssize_t apply_interval_us_show(struct kobject *kobj,
1676 struct kobj_attribute *attr, char *buf)
1677{
1678 struct damon_sysfs_scheme *scheme = container_of(kobj,
1679 struct damon_sysfs_scheme, kobj);
1680
1681 return sysfs_emit(buf, "%lu\n", scheme->apply_interval_us);
1682}
1683
1684static ssize_t apply_interval_us_store(struct kobject *kobj,
1685 struct kobj_attribute *attr, const char *buf, size_t count)
1686{
1687 struct damon_sysfs_scheme *scheme = container_of(kobj,
1688 struct damon_sysfs_scheme, kobj);
1689 int err = kstrtoul(buf, 0, &scheme->apply_interval_us);
1690
1691 return err ? err : count;
1692}
1693
1694static void damon_sysfs_scheme_release(struct kobject *kobj)
1695{
1696 kfree(container_of(kobj, struct damon_sysfs_scheme, kobj));
1697}
1698
1699static struct kobj_attribute damon_sysfs_scheme_action_attr =
1700 __ATTR_RW_MODE(action, 0600);
1701
1702static struct kobj_attribute damon_sysfs_scheme_apply_interval_us_attr =
1703 __ATTR_RW_MODE(apply_interval_us, 0600);
1704
1705static struct attribute *damon_sysfs_scheme_attrs[] = {
1706 &damon_sysfs_scheme_action_attr.attr,
1707 &damon_sysfs_scheme_apply_interval_us_attr.attr,
1708 NULL,
1709};
1710ATTRIBUTE_GROUPS(damon_sysfs_scheme);
1711
1712static const struct kobj_type damon_sysfs_scheme_ktype = {
1713 .release = damon_sysfs_scheme_release,
1714 .sysfs_ops = &kobj_sysfs_ops,
1715 .default_groups = damon_sysfs_scheme_groups,
1716};
1717
1718/*
1719 * schemes directory
1720 */
1721
1722struct damon_sysfs_schemes *damon_sysfs_schemes_alloc(void)
1723{
1724 return kzalloc(sizeof(struct damon_sysfs_schemes), GFP_KERNEL);
1725}
1726
1727void damon_sysfs_schemes_rm_dirs(struct damon_sysfs_schemes *schemes)
1728{
1729 struct damon_sysfs_scheme **schemes_arr = schemes->schemes_arr;
1730 int i;
1731
1732 for (i = 0; i < schemes->nr; i++) {
1733 damon_sysfs_scheme_rm_dirs(schemes_arr[i]);
1734 kobject_put(&schemes_arr[i]->kobj);
1735 }
1736 schemes->nr = 0;
1737 kfree(schemes_arr);
1738 schemes->schemes_arr = NULL;
1739}
1740
1741static int damon_sysfs_schemes_add_dirs(struct damon_sysfs_schemes *schemes,
1742 int nr_schemes)
1743{
1744 struct damon_sysfs_scheme **schemes_arr, *scheme;
1745 int err, i;
1746
1747 damon_sysfs_schemes_rm_dirs(schemes);
1748 if (!nr_schemes)
1749 return 0;
1750
1751 schemes_arr = kmalloc_array(nr_schemes, sizeof(*schemes_arr),
1752 GFP_KERNEL | __GFP_NOWARN);
1753 if (!schemes_arr)
1754 return -ENOMEM;
1755 schemes->schemes_arr = schemes_arr;
1756
1757 for (i = 0; i < nr_schemes; i++) {
1758 /*
1759 * apply_interval_us as 0 means same to aggregation interval
1760 * (same to before-apply_interval behavior)
1761 */
1762 scheme = damon_sysfs_scheme_alloc(DAMOS_STAT, 0);
1763 if (!scheme) {
1764 damon_sysfs_schemes_rm_dirs(schemes);
1765 return -ENOMEM;
1766 }
1767
1768 err = kobject_init_and_add(&scheme->kobj,
1769 &damon_sysfs_scheme_ktype, &schemes->kobj,
1770 "%d", i);
1771 if (err)
1772 goto out;
1773 err = damon_sysfs_scheme_add_dirs(scheme);
1774 if (err)
1775 goto out;
1776
1777 schemes_arr[i] = scheme;
1778 schemes->nr++;
1779 }
1780 return 0;
1781
1782out:
1783 damon_sysfs_schemes_rm_dirs(schemes);
1784 kobject_put(&scheme->kobj);
1785 return err;
1786}
1787
1788static ssize_t nr_schemes_show(struct kobject *kobj,
1789 struct kobj_attribute *attr, char *buf)
1790{
1791 struct damon_sysfs_schemes *schemes = container_of(kobj,
1792 struct damon_sysfs_schemes, kobj);
1793
1794 return sysfs_emit(buf, "%d\n", schemes->nr);
1795}
1796
1797static ssize_t nr_schemes_store(struct kobject *kobj,
1798 struct kobj_attribute *attr, const char *buf, size_t count)
1799{
1800 struct damon_sysfs_schemes *schemes;
1801 int nr, err = kstrtoint(buf, 0, &nr);
1802
1803 if (err)
1804 return err;
1805 if (nr < 0)
1806 return -EINVAL;
1807
1808 schemes = container_of(kobj, struct damon_sysfs_schemes, kobj);
1809
1810 if (!mutex_trylock(&damon_sysfs_lock))
1811 return -EBUSY;
1812 err = damon_sysfs_schemes_add_dirs(schemes, nr);
1813 mutex_unlock(&damon_sysfs_lock);
1814 if (err)
1815 return err;
1816 return count;
1817}
1818
1819static void damon_sysfs_schemes_release(struct kobject *kobj)
1820{
1821 kfree(container_of(kobj, struct damon_sysfs_schemes, kobj));
1822}
1823
1824static struct kobj_attribute damon_sysfs_schemes_nr_attr =
1825 __ATTR_RW_MODE(nr_schemes, 0600);
1826
1827static struct attribute *damon_sysfs_schemes_attrs[] = {
1828 &damon_sysfs_schemes_nr_attr.attr,
1829 NULL,
1830};
1831ATTRIBUTE_GROUPS(damon_sysfs_schemes);
1832
1833const struct kobj_type damon_sysfs_schemes_ktype = {
1834 .release = damon_sysfs_schemes_release,
1835 .sysfs_ops = &kobj_sysfs_ops,
1836 .default_groups = damon_sysfs_schemes_groups,
1837};
1838
1839static bool damon_sysfs_memcg_path_eq(struct mem_cgroup *memcg,
1840 char *memcg_path_buf, char *path)
1841{
1842#ifdef CONFIG_MEMCG
1843 cgroup_path(memcg->css.cgroup, memcg_path_buf, PATH_MAX);
1844 if (sysfs_streq(memcg_path_buf, path))
1845 return true;
1846#endif /* CONFIG_MEMCG */
1847 return false;
1848}
1849
1850static int damon_sysfs_memcg_path_to_id(char *memcg_path, unsigned short *id)
1851{
1852 struct mem_cgroup *memcg;
1853 char *path;
1854 bool found = false;
1855
1856 if (!memcg_path)
1857 return -EINVAL;
1858
1859 path = kmalloc(sizeof(*path) * PATH_MAX, GFP_KERNEL);
1860 if (!path)
1861 return -ENOMEM;
1862
1863 for (memcg = mem_cgroup_iter(NULL, NULL, NULL); memcg;
1864 memcg = mem_cgroup_iter(NULL, memcg, NULL)) {
1865 /* skip removed memcg */
1866 if (!mem_cgroup_id(memcg))
1867 continue;
1868 if (damon_sysfs_memcg_path_eq(memcg, path, memcg_path)) {
1869 *id = mem_cgroup_id(memcg);
1870 found = true;
1871 break;
1872 }
1873 }
1874
1875 kfree(path);
1876 return found ? 0 : -EINVAL;
1877}
1878
1879static int damon_sysfs_set_scheme_filters(struct damos *scheme,
1880 struct damon_sysfs_scheme_filters *sysfs_filters)
1881{
1882 int i;
1883 struct damos_filter *filter, *next;
1884
1885 damos_for_each_filter_safe(filter, next, scheme)
1886 damos_destroy_filter(filter);
1887
1888 for (i = 0; i < sysfs_filters->nr; i++) {
1889 struct damon_sysfs_scheme_filter *sysfs_filter =
1890 sysfs_filters->filters_arr[i];
1891 struct damos_filter *filter =
1892 damos_new_filter(sysfs_filter->type,
1893 sysfs_filter->matching);
1894 int err;
1895
1896 if (!filter)
1897 return -ENOMEM;
1898 if (filter->type == DAMOS_FILTER_TYPE_MEMCG) {
1899 err = damon_sysfs_memcg_path_to_id(
1900 sysfs_filter->memcg_path,
1901 &filter->memcg_id);
1902 if (err) {
1903 damos_destroy_filter(filter);
1904 return err;
1905 }
1906 } else if (filter->type == DAMOS_FILTER_TYPE_ADDR) {
1907 if (sysfs_filter->addr_range.end <
1908 sysfs_filter->addr_range.start) {
1909 damos_destroy_filter(filter);
1910 return -EINVAL;
1911 }
1912 filter->addr_range = sysfs_filter->addr_range;
1913 } else if (filter->type == DAMOS_FILTER_TYPE_TARGET) {
1914 filter->target_idx = sysfs_filter->target_idx;
1915 }
1916
1917 damos_add_filter(scheme, filter);
1918 }
1919 return 0;
1920}
1921
1922static int damos_sysfs_set_quota_score(
1923 struct damos_sysfs_quota_goals *sysfs_goals,
1924 struct damos_quota *quota)
1925{
1926 struct damos_quota_goal *goal, *next;
1927 int i;
1928
1929 damos_for_each_quota_goal_safe(goal, next, quota)
1930 damos_destroy_quota_goal(goal);
1931
1932 for (i = 0; i < sysfs_goals->nr; i++) {
1933 struct damos_sysfs_quota_goal *sysfs_goal =
1934 sysfs_goals->goals_arr[i];
1935
1936 if (!sysfs_goal->target_value)
1937 continue;
1938
1939 goal = damos_new_quota_goal(sysfs_goal->metric,
1940 sysfs_goal->target_value);
1941 if (!goal)
1942 return -ENOMEM;
1943 if (sysfs_goal->metric == DAMOS_QUOTA_USER_INPUT)
1944 goal->current_value = sysfs_goal->current_value;
1945 damos_add_quota_goal(quota, goal);
1946 }
1947 return 0;
1948}
1949
1950int damos_sysfs_set_quota_scores(struct damon_sysfs_schemes *sysfs_schemes,
1951 struct damon_ctx *ctx)
1952{
1953 struct damos *scheme;
1954 int i = 0;
1955
1956 damon_for_each_scheme(scheme, ctx) {
1957 struct damon_sysfs_scheme *sysfs_scheme;
1958 int err;
1959
1960 /* user could have removed the scheme sysfs dir */
1961 if (i >= sysfs_schemes->nr)
1962 break;
1963
1964 sysfs_scheme = sysfs_schemes->schemes_arr[i];
1965 err = damos_sysfs_set_quota_score(sysfs_scheme->quotas->goals,
1966 &scheme->quota);
1967 if (err)
1968 /* kdamond will clean up schemes and terminated */
1969 return err;
1970 i++;
1971 }
1972 return 0;
1973}
1974
1975void damos_sysfs_update_effective_quotas(
1976 struct damon_sysfs_schemes *sysfs_schemes,
1977 struct damon_ctx *ctx)
1978{
1979 struct damos *scheme;
1980 int schemes_idx = 0;
1981
1982 damon_for_each_scheme(scheme, ctx) {
1983 struct damon_sysfs_quotas *sysfs_quotas;
1984
1985 /* user could have removed the scheme sysfs dir */
1986 if (schemes_idx >= sysfs_schemes->nr)
1987 break;
1988
1989 sysfs_quotas =
1990 sysfs_schemes->schemes_arr[schemes_idx++]->quotas;
1991 sysfs_quotas->effective_sz = scheme->quota.esz;
1992 }
1993}
1994
1995static struct damos *damon_sysfs_mk_scheme(
1996 struct damon_sysfs_scheme *sysfs_scheme)
1997{
1998 struct damon_sysfs_access_pattern *access_pattern =
1999 sysfs_scheme->access_pattern;
2000 struct damon_sysfs_quotas *sysfs_quotas = sysfs_scheme->quotas;
2001 struct damon_sysfs_weights *sysfs_weights = sysfs_quotas->weights;
2002 struct damon_sysfs_watermarks *sysfs_wmarks = sysfs_scheme->watermarks;
2003 struct damon_sysfs_scheme_filters *sysfs_filters =
2004 sysfs_scheme->filters;
2005 struct damos *scheme;
2006 int err;
2007
2008 struct damos_access_pattern pattern = {
2009 .min_sz_region = access_pattern->sz->min,
2010 .max_sz_region = access_pattern->sz->max,
2011 .min_nr_accesses = access_pattern->nr_accesses->min,
2012 .max_nr_accesses = access_pattern->nr_accesses->max,
2013 .min_age_region = access_pattern->age->min,
2014 .max_age_region = access_pattern->age->max,
2015 };
2016 struct damos_quota quota = {
2017 .ms = sysfs_quotas->ms,
2018 .sz = sysfs_quotas->sz,
2019 .reset_interval = sysfs_quotas->reset_interval_ms,
2020 .weight_sz = sysfs_weights->sz,
2021 .weight_nr_accesses = sysfs_weights->nr_accesses,
2022 .weight_age = sysfs_weights->age,
2023 };
2024 struct damos_watermarks wmarks = {
2025 .metric = sysfs_wmarks->metric,
2026 .interval = sysfs_wmarks->interval_us,
2027 .high = sysfs_wmarks->high,
2028 .mid = sysfs_wmarks->mid,
2029 .low = sysfs_wmarks->low,
2030 };
2031
2032 scheme = damon_new_scheme(&pattern, sysfs_scheme->action,
2033 sysfs_scheme->apply_interval_us, "a, &wmarks);
2034 if (!scheme)
2035 return NULL;
2036
2037 err = damos_sysfs_set_quota_score(sysfs_quotas->goals, &scheme->quota);
2038 if (err) {
2039 damon_destroy_scheme(scheme);
2040 return NULL;
2041 }
2042
2043 err = damon_sysfs_set_scheme_filters(scheme, sysfs_filters);
2044 if (err) {
2045 damon_destroy_scheme(scheme);
2046 return NULL;
2047 }
2048 return scheme;
2049}
2050
2051static void damon_sysfs_update_scheme(struct damos *scheme,
2052 struct damon_sysfs_scheme *sysfs_scheme)
2053{
2054 struct damon_sysfs_access_pattern *access_pattern =
2055 sysfs_scheme->access_pattern;
2056 struct damon_sysfs_quotas *sysfs_quotas = sysfs_scheme->quotas;
2057 struct damon_sysfs_weights *sysfs_weights = sysfs_quotas->weights;
2058 struct damon_sysfs_watermarks *sysfs_wmarks = sysfs_scheme->watermarks;
2059 int err;
2060
2061 scheme->pattern.min_sz_region = access_pattern->sz->min;
2062 scheme->pattern.max_sz_region = access_pattern->sz->max;
2063 scheme->pattern.min_nr_accesses = access_pattern->nr_accesses->min;
2064 scheme->pattern.max_nr_accesses = access_pattern->nr_accesses->max;
2065 scheme->pattern.min_age_region = access_pattern->age->min;
2066 scheme->pattern.max_age_region = access_pattern->age->max;
2067
2068 scheme->action = sysfs_scheme->action;
2069 scheme->apply_interval_us = sysfs_scheme->apply_interval_us;
2070
2071 scheme->quota.ms = sysfs_quotas->ms;
2072 scheme->quota.sz = sysfs_quotas->sz;
2073 scheme->quota.reset_interval = sysfs_quotas->reset_interval_ms;
2074 scheme->quota.weight_sz = sysfs_weights->sz;
2075 scheme->quota.weight_nr_accesses = sysfs_weights->nr_accesses;
2076 scheme->quota.weight_age = sysfs_weights->age;
2077
2078 err = damos_sysfs_set_quota_score(sysfs_quotas->goals, &scheme->quota);
2079 if (err) {
2080 damon_destroy_scheme(scheme);
2081 return;
2082 }
2083
2084 scheme->wmarks.metric = sysfs_wmarks->metric;
2085 scheme->wmarks.interval = sysfs_wmarks->interval_us;
2086 scheme->wmarks.high = sysfs_wmarks->high;
2087 scheme->wmarks.mid = sysfs_wmarks->mid;
2088 scheme->wmarks.low = sysfs_wmarks->low;
2089
2090 err = damon_sysfs_set_scheme_filters(scheme, sysfs_scheme->filters);
2091 if (err)
2092 damon_destroy_scheme(scheme);
2093}
2094
2095int damon_sysfs_set_schemes(struct damon_ctx *ctx,
2096 struct damon_sysfs_schemes *sysfs_schemes)
2097{
2098 struct damos *scheme, *next;
2099 int i = 0;
2100
2101 damon_for_each_scheme_safe(scheme, next, ctx) {
2102 if (i < sysfs_schemes->nr)
2103 damon_sysfs_update_scheme(scheme,
2104 sysfs_schemes->schemes_arr[i]);
2105 else
2106 damon_destroy_scheme(scheme);
2107 i++;
2108 }
2109
2110 for (; i < sysfs_schemes->nr; i++) {
2111 struct damos *scheme, *next;
2112
2113 scheme = damon_sysfs_mk_scheme(sysfs_schemes->schemes_arr[i]);
2114 if (!scheme) {
2115 damon_for_each_scheme_safe(scheme, next, ctx)
2116 damon_destroy_scheme(scheme);
2117 return -ENOMEM;
2118 }
2119 damon_add_scheme(ctx, scheme);
2120 }
2121 return 0;
2122}
2123
2124void damon_sysfs_schemes_update_stats(
2125 struct damon_sysfs_schemes *sysfs_schemes,
2126 struct damon_ctx *ctx)
2127{
2128 struct damos *scheme;
2129 int schemes_idx = 0;
2130
2131 damon_for_each_scheme(scheme, ctx) {
2132 struct damon_sysfs_stats *sysfs_stats;
2133
2134 /* user could have removed the scheme sysfs dir */
2135 if (schemes_idx >= sysfs_schemes->nr)
2136 break;
2137
2138 sysfs_stats = sysfs_schemes->schemes_arr[schemes_idx++]->stats;
2139 sysfs_stats->nr_tried = scheme->stat.nr_tried;
2140 sysfs_stats->sz_tried = scheme->stat.sz_tried;
2141 sysfs_stats->nr_applied = scheme->stat.nr_applied;
2142 sysfs_stats->sz_applied = scheme->stat.sz_applied;
2143 sysfs_stats->qt_exceeds = scheme->stat.qt_exceeds;
2144 }
2145}
2146
2147/*
2148 * damon_sysfs_schemes that need to update its schemes regions dir. Protected
2149 * by damon_sysfs_lock
2150 */
2151static struct damon_sysfs_schemes *damon_sysfs_schemes_for_damos_callback;
2152static int damon_sysfs_schemes_region_idx;
2153static bool damos_regions_upd_total_bytes_only;
2154
2155/*
2156 * DAMON callback that called before damos apply. While this callback is
2157 * registered, damon_sysfs_lock should be held to ensure the regions
2158 * directories exist.
2159 */
2160static int damon_sysfs_before_damos_apply(struct damon_ctx *ctx,
2161 struct damon_target *t, struct damon_region *r,
2162 struct damos *s)
2163{
2164 struct damos *scheme;
2165 struct damon_sysfs_scheme_regions *sysfs_regions;
2166 struct damon_sysfs_scheme_region *region;
2167 struct damon_sysfs_schemes *sysfs_schemes =
2168 damon_sysfs_schemes_for_damos_callback;
2169 int schemes_idx = 0;
2170
2171 damon_for_each_scheme(scheme, ctx) {
2172 if (scheme == s)
2173 break;
2174 schemes_idx++;
2175 }
2176
2177 /* user could have removed the scheme sysfs dir */
2178 if (schemes_idx >= sysfs_schemes->nr)
2179 return 0;
2180
2181 sysfs_regions = sysfs_schemes->schemes_arr[schemes_idx]->tried_regions;
2182 if (sysfs_regions->upd_status == DAMOS_TRIED_REGIONS_UPD_FINISHED)
2183 return 0;
2184 if (sysfs_regions->upd_status == DAMOS_TRIED_REGIONS_UPD_IDLE)
2185 sysfs_regions->upd_status = DAMOS_TRIED_REGIONS_UPD_STARTED;
2186 sysfs_regions->total_bytes += r->ar.end - r->ar.start;
2187 if (damos_regions_upd_total_bytes_only)
2188 return 0;
2189
2190 region = damon_sysfs_scheme_region_alloc(r);
2191 if (!region)
2192 return 0;
2193 list_add_tail(®ion->list, &sysfs_regions->regions_list);
2194 sysfs_regions->nr_regions++;
2195 if (kobject_init_and_add(®ion->kobj,
2196 &damon_sysfs_scheme_region_ktype,
2197 &sysfs_regions->kobj, "%d",
2198 damon_sysfs_schemes_region_idx++)) {
2199 kobject_put(®ion->kobj);
2200 }
2201 return 0;
2202}
2203
2204/*
2205 * DAMON callback that called after each accesses sampling. While this
2206 * callback is registered, damon_sysfs_lock should be held to ensure the
2207 * regions directories exist.
2208 */
2209void damos_sysfs_mark_finished_regions_updates(struct damon_ctx *ctx)
2210{
2211 struct damon_sysfs_schemes *sysfs_schemes =
2212 damon_sysfs_schemes_for_damos_callback;
2213 struct damon_sysfs_scheme_regions *sysfs_regions;
2214 int i;
2215
2216 for (i = 0; i < sysfs_schemes->nr; i++) {
2217 sysfs_regions = sysfs_schemes->schemes_arr[i]->tried_regions;
2218 if (sysfs_regions->upd_status ==
2219 DAMOS_TRIED_REGIONS_UPD_STARTED ||
2220 time_after(jiffies,
2221 sysfs_regions->upd_timeout_jiffies))
2222 sysfs_regions->upd_status =
2223 DAMOS_TRIED_REGIONS_UPD_FINISHED;
2224 }
2225}
2226
2227/* Called from damon_sysfs_cmd_request_callback under damon_sysfs_lock */
2228int damon_sysfs_schemes_clear_regions(
2229 struct damon_sysfs_schemes *sysfs_schemes,
2230 struct damon_ctx *ctx)
2231{
2232 struct damos *scheme;
2233 int schemes_idx = 0;
2234
2235 damon_for_each_scheme(scheme, ctx) {
2236 struct damon_sysfs_scheme *sysfs_scheme;
2237
2238 /* user could have removed the scheme sysfs dir */
2239 if (schemes_idx >= sysfs_schemes->nr)
2240 break;
2241
2242 sysfs_scheme = sysfs_schemes->schemes_arr[schemes_idx++];
2243 damon_sysfs_scheme_regions_rm_dirs(
2244 sysfs_scheme->tried_regions);
2245 sysfs_scheme->tried_regions->total_bytes = 0;
2246 }
2247 return 0;
2248}
2249
2250static struct damos *damos_sysfs_nth_scheme(int n, struct damon_ctx *ctx)
2251{
2252 struct damos *scheme;
2253 int i = 0;
2254
2255 damon_for_each_scheme(scheme, ctx) {
2256 if (i == n)
2257 return scheme;
2258 i++;
2259 }
2260 return NULL;
2261}
2262
2263static void damos_tried_regions_init_upd_status(
2264 struct damon_sysfs_schemes *sysfs_schemes,
2265 struct damon_ctx *ctx)
2266{
2267 int i;
2268 struct damos *scheme;
2269 struct damon_sysfs_scheme_regions *sysfs_regions;
2270
2271 for (i = 0; i < sysfs_schemes->nr; i++) {
2272 sysfs_regions = sysfs_schemes->schemes_arr[i]->tried_regions;
2273 scheme = damos_sysfs_nth_scheme(i, ctx);
2274 if (!scheme) {
2275 sysfs_regions->upd_status =
2276 DAMOS_TRIED_REGIONS_UPD_FINISHED;
2277 continue;
2278 }
2279 sysfs_regions->upd_status = DAMOS_TRIED_REGIONS_UPD_IDLE;
2280 sysfs_regions->upd_timeout_jiffies = jiffies +
2281 2 * usecs_to_jiffies(scheme->apply_interval_us ?
2282 scheme->apply_interval_us :
2283 ctx->attrs.aggr_interval);
2284 }
2285}
2286
2287/* Called from damon_sysfs_cmd_request_callback under damon_sysfs_lock */
2288int damon_sysfs_schemes_update_regions_start(
2289 struct damon_sysfs_schemes *sysfs_schemes,
2290 struct damon_ctx *ctx, bool total_bytes_only)
2291{
2292 damon_sysfs_schemes_clear_regions(sysfs_schemes, ctx);
2293 damon_sysfs_schemes_for_damos_callback = sysfs_schemes;
2294 damos_tried_regions_init_upd_status(sysfs_schemes, ctx);
2295 damos_regions_upd_total_bytes_only = total_bytes_only;
2296 ctx->callback.before_damos_apply = damon_sysfs_before_damos_apply;
2297 return 0;
2298}
2299
2300bool damos_sysfs_regions_upd_done(void)
2301{
2302 struct damon_sysfs_schemes *sysfs_schemes =
2303 damon_sysfs_schemes_for_damos_callback;
2304 struct damon_sysfs_scheme_regions *sysfs_regions;
2305 int i;
2306
2307 for (i = 0; i < sysfs_schemes->nr; i++) {
2308 sysfs_regions = sysfs_schemes->schemes_arr[i]->tried_regions;
2309 if (sysfs_regions->upd_status !=
2310 DAMOS_TRIED_REGIONS_UPD_FINISHED)
2311 return false;
2312 }
2313 return true;
2314}
2315
2316/*
2317 * Called from damon_sysfs_cmd_request_callback under damon_sysfs_lock. Caller
2318 * should unlock damon_sysfs_lock which held before
2319 * damon_sysfs_schemes_update_regions_start()
2320 */
2321int damon_sysfs_schemes_update_regions_stop(struct damon_ctx *ctx)
2322{
2323 damon_sysfs_schemes_for_damos_callback = NULL;
2324 ctx->callback.before_damos_apply = NULL;
2325 damon_sysfs_schemes_region_idx = 0;
2326 return 0;
2327}