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