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