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