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