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