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