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