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
10 #include "sysfs-common.h"
11
12 /*
13 * scheme region directory
14 */
15
16 struct damon_sysfs_scheme_region {
17 struct kobject kobj;
18 struct damon_addr_range ar;
19 unsigned int nr_accesses;
20 unsigned int age;
21 struct list_head list;
22 };
23
damon_sysfs_scheme_region_alloc(struct damon_region * region)24 static struct damon_sysfs_scheme_region *damon_sysfs_scheme_region_alloc(
25 struct damon_region *region)
26 {
27 struct damon_sysfs_scheme_region *sysfs_region = kmalloc(
28 sizeof(*sysfs_region), GFP_KERNEL);
29
30 if (!sysfs_region)
31 return NULL;
32 sysfs_region->kobj = (struct kobject){};
33 sysfs_region->ar = region->ar;
34 sysfs_region->nr_accesses = region->nr_accesses;
35 sysfs_region->age = region->age;
36 INIT_LIST_HEAD(&sysfs_region->list);
37 return sysfs_region;
38 }
39
start_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)40 static ssize_t start_show(struct kobject *kobj, struct kobj_attribute *attr,
41 char *buf)
42 {
43 struct damon_sysfs_scheme_region *region = container_of(kobj,
44 struct damon_sysfs_scheme_region, kobj);
45
46 return sysfs_emit(buf, "%lu\n", region->ar.start);
47 }
48
end_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)49 static ssize_t end_show(struct kobject *kobj, struct kobj_attribute *attr,
50 char *buf)
51 {
52 struct damon_sysfs_scheme_region *region = container_of(kobj,
53 struct damon_sysfs_scheme_region, kobj);
54
55 return sysfs_emit(buf, "%lu\n", region->ar.end);
56 }
57
nr_accesses_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)58 static ssize_t nr_accesses_show(struct kobject *kobj,
59 struct kobj_attribute *attr, char *buf)
60 {
61 struct damon_sysfs_scheme_region *region = container_of(kobj,
62 struct damon_sysfs_scheme_region, kobj);
63
64 return sysfs_emit(buf, "%u\n", region->nr_accesses);
65 }
66
age_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)67 static ssize_t age_show(struct kobject *kobj, struct kobj_attribute *attr,
68 char *buf)
69 {
70 struct damon_sysfs_scheme_region *region = container_of(kobj,
71 struct damon_sysfs_scheme_region, kobj);
72
73 return sysfs_emit(buf, "%u\n", region->age);
74 }
75
damon_sysfs_scheme_region_release(struct kobject * kobj)76 static void damon_sysfs_scheme_region_release(struct kobject *kobj)
77 {
78 struct damon_sysfs_scheme_region *region = container_of(kobj,
79 struct damon_sysfs_scheme_region, kobj);
80
81 list_del(®ion->list);
82 kfree(region);
83 }
84
85 static struct kobj_attribute damon_sysfs_scheme_region_start_attr =
86 __ATTR_RO_MODE(start, 0400);
87
88 static struct kobj_attribute damon_sysfs_scheme_region_end_attr =
89 __ATTR_RO_MODE(end, 0400);
90
91 static struct kobj_attribute damon_sysfs_scheme_region_nr_accesses_attr =
92 __ATTR_RO_MODE(nr_accesses, 0400);
93
94 static struct kobj_attribute damon_sysfs_scheme_region_age_attr =
95 __ATTR_RO_MODE(age, 0400);
96
97 static struct attribute *damon_sysfs_scheme_region_attrs[] = {
98 &damon_sysfs_scheme_region_start_attr.attr,
99 &damon_sysfs_scheme_region_end_attr.attr,
100 &damon_sysfs_scheme_region_nr_accesses_attr.attr,
101 &damon_sysfs_scheme_region_age_attr.attr,
102 NULL,
103 };
104 ATTRIBUTE_GROUPS(damon_sysfs_scheme_region);
105
106 static const struct kobj_type damon_sysfs_scheme_region_ktype = {
107 .release = damon_sysfs_scheme_region_release,
108 .sysfs_ops = &kobj_sysfs_ops,
109 .default_groups = damon_sysfs_scheme_region_groups,
110 };
111
112 /*
113 * scheme regions directory
114 */
115
116 struct damon_sysfs_scheme_regions {
117 struct kobject kobj;
118 struct list_head regions_list;
119 int nr_regions;
120 };
121
122 static struct damon_sysfs_scheme_regions *
damon_sysfs_scheme_regions_alloc(void)123 damon_sysfs_scheme_regions_alloc(void)
124 {
125 struct damon_sysfs_scheme_regions *regions = kmalloc(sizeof(*regions),
126 GFP_KERNEL);
127
128 regions->kobj = (struct kobject){};
129 INIT_LIST_HEAD(®ions->regions_list);
130 regions->nr_regions = 0;
131 return regions;
132 }
133
damon_sysfs_scheme_regions_rm_dirs(struct damon_sysfs_scheme_regions * regions)134 static void damon_sysfs_scheme_regions_rm_dirs(
135 struct damon_sysfs_scheme_regions *regions)
136 {
137 struct damon_sysfs_scheme_region *r, *next;
138
139 list_for_each_entry_safe(r, next, ®ions->regions_list, list) {
140 /* release function deletes it from the list */
141 kobject_put(&r->kobj);
142 regions->nr_regions--;
143 }
144 }
145
damon_sysfs_scheme_regions_release(struct kobject * kobj)146 static void damon_sysfs_scheme_regions_release(struct kobject *kobj)
147 {
148 kfree(container_of(kobj, struct damon_sysfs_scheme_regions, kobj));
149 }
150
151 static struct attribute *damon_sysfs_scheme_regions_attrs[] = {
152 NULL,
153 };
154 ATTRIBUTE_GROUPS(damon_sysfs_scheme_regions);
155
156 static const struct kobj_type damon_sysfs_scheme_regions_ktype = {
157 .release = damon_sysfs_scheme_regions_release,
158 .sysfs_ops = &kobj_sysfs_ops,
159 .default_groups = damon_sysfs_scheme_regions_groups,
160 };
161
162 /*
163 * schemes/stats directory
164 */
165
166 struct damon_sysfs_stats {
167 struct kobject kobj;
168 unsigned long nr_tried;
169 unsigned long sz_tried;
170 unsigned long nr_applied;
171 unsigned long sz_applied;
172 unsigned long qt_exceeds;
173 };
174
damon_sysfs_stats_alloc(void)175 static struct damon_sysfs_stats *damon_sysfs_stats_alloc(void)
176 {
177 return kzalloc(sizeof(struct damon_sysfs_stats), GFP_KERNEL);
178 }
179
nr_tried_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)180 static ssize_t nr_tried_show(struct kobject *kobj, struct kobj_attribute *attr,
181 char *buf)
182 {
183 struct damon_sysfs_stats *stats = container_of(kobj,
184 struct damon_sysfs_stats, kobj);
185
186 return sysfs_emit(buf, "%lu\n", stats->nr_tried);
187 }
188
sz_tried_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)189 static ssize_t sz_tried_show(struct kobject *kobj, struct kobj_attribute *attr,
190 char *buf)
191 {
192 struct damon_sysfs_stats *stats = container_of(kobj,
193 struct damon_sysfs_stats, kobj);
194
195 return sysfs_emit(buf, "%lu\n", stats->sz_tried);
196 }
197
nr_applied_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)198 static ssize_t nr_applied_show(struct kobject *kobj,
199 struct kobj_attribute *attr, char *buf)
200 {
201 struct damon_sysfs_stats *stats = container_of(kobj,
202 struct damon_sysfs_stats, kobj);
203
204 return sysfs_emit(buf, "%lu\n", stats->nr_applied);
205 }
206
sz_applied_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)207 static ssize_t sz_applied_show(struct kobject *kobj,
208 struct kobj_attribute *attr, char *buf)
209 {
210 struct damon_sysfs_stats *stats = container_of(kobj,
211 struct damon_sysfs_stats, kobj);
212
213 return sysfs_emit(buf, "%lu\n", stats->sz_applied);
214 }
215
qt_exceeds_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)216 static ssize_t qt_exceeds_show(struct kobject *kobj,
217 struct kobj_attribute *attr, char *buf)
218 {
219 struct damon_sysfs_stats *stats = container_of(kobj,
220 struct damon_sysfs_stats, kobj);
221
222 return sysfs_emit(buf, "%lu\n", stats->qt_exceeds);
223 }
224
damon_sysfs_stats_release(struct kobject * kobj)225 static void damon_sysfs_stats_release(struct kobject *kobj)
226 {
227 kfree(container_of(kobj, struct damon_sysfs_stats, kobj));
228 }
229
230 static struct kobj_attribute damon_sysfs_stats_nr_tried_attr =
231 __ATTR_RO_MODE(nr_tried, 0400);
232
233 static struct kobj_attribute damon_sysfs_stats_sz_tried_attr =
234 __ATTR_RO_MODE(sz_tried, 0400);
235
236 static struct kobj_attribute damon_sysfs_stats_nr_applied_attr =
237 __ATTR_RO_MODE(nr_applied, 0400);
238
239 static struct kobj_attribute damon_sysfs_stats_sz_applied_attr =
240 __ATTR_RO_MODE(sz_applied, 0400);
241
242 static struct kobj_attribute damon_sysfs_stats_qt_exceeds_attr =
243 __ATTR_RO_MODE(qt_exceeds, 0400);
244
245 static struct attribute *damon_sysfs_stats_attrs[] = {
246 &damon_sysfs_stats_nr_tried_attr.attr,
247 &damon_sysfs_stats_sz_tried_attr.attr,
248 &damon_sysfs_stats_nr_applied_attr.attr,
249 &damon_sysfs_stats_sz_applied_attr.attr,
250 &damon_sysfs_stats_qt_exceeds_attr.attr,
251 NULL,
252 };
253 ATTRIBUTE_GROUPS(damon_sysfs_stats);
254
255 static const struct kobj_type damon_sysfs_stats_ktype = {
256 .release = damon_sysfs_stats_release,
257 .sysfs_ops = &kobj_sysfs_ops,
258 .default_groups = damon_sysfs_stats_groups,
259 };
260
261 /*
262 * filter directory
263 */
264
265 struct damon_sysfs_scheme_filter {
266 struct kobject kobj;
267 enum damos_filter_type type;
268 bool matching;
269 char *memcg_path;
270 };
271
damon_sysfs_scheme_filter_alloc(void)272 static struct damon_sysfs_scheme_filter *damon_sysfs_scheme_filter_alloc(void)
273 {
274 return kzalloc(sizeof(struct damon_sysfs_scheme_filter), GFP_KERNEL);
275 }
276
277 /* Should match with enum damos_filter_type */
278 static const char * const damon_sysfs_scheme_filter_type_strs[] = {
279 "anon",
280 "memcg",
281 };
282
type_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)283 static ssize_t type_show(struct kobject *kobj,
284 struct kobj_attribute *attr, char *buf)
285 {
286 struct damon_sysfs_scheme_filter *filter = container_of(kobj,
287 struct damon_sysfs_scheme_filter, kobj);
288
289 return sysfs_emit(buf, "%s\n",
290 damon_sysfs_scheme_filter_type_strs[filter->type]);
291 }
292
type_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t count)293 static ssize_t type_store(struct kobject *kobj,
294 struct kobj_attribute *attr, const char *buf, size_t count)
295 {
296 struct damon_sysfs_scheme_filter *filter = container_of(kobj,
297 struct damon_sysfs_scheme_filter, kobj);
298 enum damos_filter_type type;
299 ssize_t ret = -EINVAL;
300
301 for (type = 0; type < NR_DAMOS_FILTER_TYPES; type++) {
302 if (sysfs_streq(buf, damon_sysfs_scheme_filter_type_strs[
303 type])) {
304 filter->type = type;
305 ret = count;
306 break;
307 }
308 }
309 return ret;
310 }
311
matching_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)312 static ssize_t matching_show(struct kobject *kobj,
313 struct kobj_attribute *attr, char *buf)
314 {
315 struct damon_sysfs_scheme_filter *filter = container_of(kobj,
316 struct damon_sysfs_scheme_filter, kobj);
317
318 return sysfs_emit(buf, "%c\n", filter->matching ? 'Y' : 'N');
319 }
320
matching_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t count)321 static ssize_t matching_store(struct kobject *kobj,
322 struct kobj_attribute *attr, const char *buf, size_t count)
323 {
324 struct damon_sysfs_scheme_filter *filter = container_of(kobj,
325 struct damon_sysfs_scheme_filter, kobj);
326 bool matching;
327 int err = kstrtobool(buf, &matching);
328
329 if (err)
330 return err;
331
332 filter->matching = matching;
333 return count;
334 }
335
memcg_path_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)336 static ssize_t memcg_path_show(struct kobject *kobj,
337 struct kobj_attribute *attr, char *buf)
338 {
339 struct damon_sysfs_scheme_filter *filter = container_of(kobj,
340 struct damon_sysfs_scheme_filter, kobj);
341
342 return sysfs_emit(buf, "%s\n",
343 filter->memcg_path ? filter->memcg_path : "");
344 }
345
memcg_path_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t count)346 static ssize_t memcg_path_store(struct kobject *kobj,
347 struct kobj_attribute *attr, const char *buf, size_t count)
348 {
349 struct damon_sysfs_scheme_filter *filter = container_of(kobj,
350 struct damon_sysfs_scheme_filter, kobj);
351 char *path = kmalloc(sizeof(*path) * (count + 1), GFP_KERNEL);
352
353 if (!path)
354 return -ENOMEM;
355
356 strscpy(path, buf, count + 1);
357 filter->memcg_path = path;
358 return count;
359 }
360
damon_sysfs_scheme_filter_release(struct kobject * kobj)361 static void damon_sysfs_scheme_filter_release(struct kobject *kobj)
362 {
363 struct damon_sysfs_scheme_filter *filter = container_of(kobj,
364 struct damon_sysfs_scheme_filter, kobj);
365
366 kfree(filter->memcg_path);
367 kfree(filter);
368 }
369
370 static struct kobj_attribute damon_sysfs_scheme_filter_type_attr =
371 __ATTR_RW_MODE(type, 0600);
372
373 static struct kobj_attribute damon_sysfs_scheme_filter_matching_attr =
374 __ATTR_RW_MODE(matching, 0600);
375
376 static struct kobj_attribute damon_sysfs_scheme_filter_memcg_path_attr =
377 __ATTR_RW_MODE(memcg_path, 0600);
378
379 static struct attribute *damon_sysfs_scheme_filter_attrs[] = {
380 &damon_sysfs_scheme_filter_type_attr.attr,
381 &damon_sysfs_scheme_filter_matching_attr.attr,
382 &damon_sysfs_scheme_filter_memcg_path_attr.attr,
383 NULL,
384 };
385 ATTRIBUTE_GROUPS(damon_sysfs_scheme_filter);
386
387 static struct kobj_type damon_sysfs_scheme_filter_ktype = {
388 .release = damon_sysfs_scheme_filter_release,
389 .sysfs_ops = &kobj_sysfs_ops,
390 .default_groups = damon_sysfs_scheme_filter_groups,
391 };
392
393 /*
394 * filters directory
395 */
396
397 struct damon_sysfs_scheme_filters {
398 struct kobject kobj;
399 struct damon_sysfs_scheme_filter **filters_arr;
400 int nr;
401 };
402
403 static struct damon_sysfs_scheme_filters *
damon_sysfs_scheme_filters_alloc(void)404 damon_sysfs_scheme_filters_alloc(void)
405 {
406 return kzalloc(sizeof(struct damon_sysfs_scheme_filters), GFP_KERNEL);
407 }
408
damon_sysfs_scheme_filters_rm_dirs(struct damon_sysfs_scheme_filters * filters)409 static void damon_sysfs_scheme_filters_rm_dirs(
410 struct damon_sysfs_scheme_filters *filters)
411 {
412 struct damon_sysfs_scheme_filter **filters_arr = filters->filters_arr;
413 int i;
414
415 for (i = 0; i < filters->nr; i++)
416 kobject_put(&filters_arr[i]->kobj);
417 filters->nr = 0;
418 kfree(filters_arr);
419 filters->filters_arr = NULL;
420 }
421
damon_sysfs_scheme_filters_add_dirs(struct damon_sysfs_scheme_filters * filters,int nr_filters)422 static int damon_sysfs_scheme_filters_add_dirs(
423 struct damon_sysfs_scheme_filters *filters, int nr_filters)
424 {
425 struct damon_sysfs_scheme_filter **filters_arr, *filter;
426 int err, i;
427
428 damon_sysfs_scheme_filters_rm_dirs(filters);
429 if (!nr_filters)
430 return 0;
431
432 filters_arr = kmalloc_array(nr_filters, sizeof(*filters_arr),
433 GFP_KERNEL | __GFP_NOWARN);
434 if (!filters_arr)
435 return -ENOMEM;
436 filters->filters_arr = filters_arr;
437
438 for (i = 0; i < nr_filters; i++) {
439 filter = damon_sysfs_scheme_filter_alloc();
440 if (!filter) {
441 damon_sysfs_scheme_filters_rm_dirs(filters);
442 return -ENOMEM;
443 }
444
445 err = kobject_init_and_add(&filter->kobj,
446 &damon_sysfs_scheme_filter_ktype,
447 &filters->kobj, "%d", i);
448 if (err) {
449 kobject_put(&filter->kobj);
450 damon_sysfs_scheme_filters_rm_dirs(filters);
451 return err;
452 }
453
454 filters_arr[i] = filter;
455 filters->nr++;
456 }
457 return 0;
458 }
459
nr_filters_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)460 static ssize_t nr_filters_show(struct kobject *kobj,
461 struct kobj_attribute *attr, char *buf)
462 {
463 struct damon_sysfs_scheme_filters *filters = container_of(kobj,
464 struct damon_sysfs_scheme_filters, kobj);
465
466 return sysfs_emit(buf, "%d\n", filters->nr);
467 }
468
nr_filters_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t count)469 static ssize_t nr_filters_store(struct kobject *kobj,
470 struct kobj_attribute *attr, const char *buf, size_t count)
471 {
472 struct damon_sysfs_scheme_filters *filters;
473 int nr, err = kstrtoint(buf, 0, &nr);
474
475 if (err)
476 return err;
477 if (nr < 0)
478 return -EINVAL;
479
480 filters = container_of(kobj, struct damon_sysfs_scheme_filters, kobj);
481
482 if (!mutex_trylock(&damon_sysfs_lock))
483 return -EBUSY;
484 err = damon_sysfs_scheme_filters_add_dirs(filters, nr);
485 mutex_unlock(&damon_sysfs_lock);
486 if (err)
487 return err;
488
489 return count;
490 }
491
damon_sysfs_scheme_filters_release(struct kobject * kobj)492 static void damon_sysfs_scheme_filters_release(struct kobject *kobj)
493 {
494 kfree(container_of(kobj, struct damon_sysfs_scheme_filters, kobj));
495 }
496
497 static struct kobj_attribute damon_sysfs_scheme_filters_nr_attr =
498 __ATTR_RW_MODE(nr_filters, 0600);
499
500 static struct attribute *damon_sysfs_scheme_filters_attrs[] = {
501 &damon_sysfs_scheme_filters_nr_attr.attr,
502 NULL,
503 };
504 ATTRIBUTE_GROUPS(damon_sysfs_scheme_filters);
505
506 static struct kobj_type damon_sysfs_scheme_filters_ktype = {
507 .release = damon_sysfs_scheme_filters_release,
508 .sysfs_ops = &kobj_sysfs_ops,
509 .default_groups = damon_sysfs_scheme_filters_groups,
510 };
511
512 /*
513 * watermarks directory
514 */
515
516 struct damon_sysfs_watermarks {
517 struct kobject kobj;
518 enum damos_wmark_metric metric;
519 unsigned long interval_us;
520 unsigned long high;
521 unsigned long mid;
522 unsigned long low;
523 };
524
damon_sysfs_watermarks_alloc(enum damos_wmark_metric metric,unsigned long interval_us,unsigned long high,unsigned long mid,unsigned long low)525 static struct damon_sysfs_watermarks *damon_sysfs_watermarks_alloc(
526 enum damos_wmark_metric metric, unsigned long interval_us,
527 unsigned long high, unsigned long mid, unsigned long low)
528 {
529 struct damon_sysfs_watermarks *watermarks = kmalloc(
530 sizeof(*watermarks), GFP_KERNEL);
531
532 if (!watermarks)
533 return NULL;
534 watermarks->kobj = (struct kobject){};
535 watermarks->metric = metric;
536 watermarks->interval_us = interval_us;
537 watermarks->high = high;
538 watermarks->mid = mid;
539 watermarks->low = low;
540 return watermarks;
541 }
542
543 /* Should match with enum damos_wmark_metric */
544 static const char * const damon_sysfs_wmark_metric_strs[] = {
545 "none",
546 "free_mem_rate",
547 };
548
metric_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)549 static ssize_t metric_show(struct kobject *kobj, struct kobj_attribute *attr,
550 char *buf)
551 {
552 struct damon_sysfs_watermarks *watermarks = container_of(kobj,
553 struct damon_sysfs_watermarks, kobj);
554
555 return sysfs_emit(buf, "%s\n",
556 damon_sysfs_wmark_metric_strs[watermarks->metric]);
557 }
558
metric_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t count)559 static ssize_t metric_store(struct kobject *kobj, struct kobj_attribute *attr,
560 const char *buf, size_t count)
561 {
562 struct damon_sysfs_watermarks *watermarks = container_of(kobj,
563 struct damon_sysfs_watermarks, kobj);
564 enum damos_wmark_metric metric;
565
566 for (metric = 0; metric < NR_DAMOS_WMARK_METRICS; metric++) {
567 if (sysfs_streq(buf, damon_sysfs_wmark_metric_strs[metric])) {
568 watermarks->metric = metric;
569 return count;
570 }
571 }
572 return -EINVAL;
573 }
574
interval_us_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)575 static ssize_t interval_us_show(struct kobject *kobj,
576 struct kobj_attribute *attr, char *buf)
577 {
578 struct damon_sysfs_watermarks *watermarks = container_of(kobj,
579 struct damon_sysfs_watermarks, kobj);
580
581 return sysfs_emit(buf, "%lu\n", watermarks->interval_us);
582 }
583
interval_us_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t count)584 static ssize_t interval_us_store(struct kobject *kobj,
585 struct kobj_attribute *attr, const char *buf, size_t count)
586 {
587 struct damon_sysfs_watermarks *watermarks = container_of(kobj,
588 struct damon_sysfs_watermarks, kobj);
589 int err = kstrtoul(buf, 0, &watermarks->interval_us);
590
591 return err ? err : count;
592 }
593
high_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)594 static ssize_t high_show(struct kobject *kobj,
595 struct kobj_attribute *attr, char *buf)
596 {
597 struct damon_sysfs_watermarks *watermarks = container_of(kobj,
598 struct damon_sysfs_watermarks, kobj);
599
600 return sysfs_emit(buf, "%lu\n", watermarks->high);
601 }
602
high_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t count)603 static ssize_t high_store(struct kobject *kobj,
604 struct kobj_attribute *attr, const char *buf, size_t count)
605 {
606 struct damon_sysfs_watermarks *watermarks = container_of(kobj,
607 struct damon_sysfs_watermarks, kobj);
608 int err = kstrtoul(buf, 0, &watermarks->high);
609
610 return err ? err : count;
611 }
612
mid_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)613 static ssize_t mid_show(struct kobject *kobj,
614 struct kobj_attribute *attr, char *buf)
615 {
616 struct damon_sysfs_watermarks *watermarks = container_of(kobj,
617 struct damon_sysfs_watermarks, kobj);
618
619 return sysfs_emit(buf, "%lu\n", watermarks->mid);
620 }
621
mid_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t count)622 static ssize_t mid_store(struct kobject *kobj,
623 struct kobj_attribute *attr, const char *buf, size_t count)
624 {
625 struct damon_sysfs_watermarks *watermarks = container_of(kobj,
626 struct damon_sysfs_watermarks, kobj);
627 int err = kstrtoul(buf, 0, &watermarks->mid);
628
629 return err ? err : count;
630 }
631
low_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)632 static ssize_t low_show(struct kobject *kobj,
633 struct kobj_attribute *attr, char *buf)
634 {
635 struct damon_sysfs_watermarks *watermarks = container_of(kobj,
636 struct damon_sysfs_watermarks, kobj);
637
638 return sysfs_emit(buf, "%lu\n", watermarks->low);
639 }
640
low_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t count)641 static ssize_t low_store(struct kobject *kobj,
642 struct kobj_attribute *attr, const char *buf, size_t count)
643 {
644 struct damon_sysfs_watermarks *watermarks = container_of(kobj,
645 struct damon_sysfs_watermarks, kobj);
646 int err = kstrtoul(buf, 0, &watermarks->low);
647
648 return err ? err : count;
649 }
650
damon_sysfs_watermarks_release(struct kobject * kobj)651 static void damon_sysfs_watermarks_release(struct kobject *kobj)
652 {
653 kfree(container_of(kobj, struct damon_sysfs_watermarks, kobj));
654 }
655
656 static struct kobj_attribute damon_sysfs_watermarks_metric_attr =
657 __ATTR_RW_MODE(metric, 0600);
658
659 static struct kobj_attribute damon_sysfs_watermarks_interval_us_attr =
660 __ATTR_RW_MODE(interval_us, 0600);
661
662 static struct kobj_attribute damon_sysfs_watermarks_high_attr =
663 __ATTR_RW_MODE(high, 0600);
664
665 static struct kobj_attribute damon_sysfs_watermarks_mid_attr =
666 __ATTR_RW_MODE(mid, 0600);
667
668 static struct kobj_attribute damon_sysfs_watermarks_low_attr =
669 __ATTR_RW_MODE(low, 0600);
670
671 static struct attribute *damon_sysfs_watermarks_attrs[] = {
672 &damon_sysfs_watermarks_metric_attr.attr,
673 &damon_sysfs_watermarks_interval_us_attr.attr,
674 &damon_sysfs_watermarks_high_attr.attr,
675 &damon_sysfs_watermarks_mid_attr.attr,
676 &damon_sysfs_watermarks_low_attr.attr,
677 NULL,
678 };
679 ATTRIBUTE_GROUPS(damon_sysfs_watermarks);
680
681 static const struct kobj_type damon_sysfs_watermarks_ktype = {
682 .release = damon_sysfs_watermarks_release,
683 .sysfs_ops = &kobj_sysfs_ops,
684 .default_groups = damon_sysfs_watermarks_groups,
685 };
686
687 /*
688 * scheme/weights directory
689 */
690
691 struct damon_sysfs_weights {
692 struct kobject kobj;
693 unsigned int sz;
694 unsigned int nr_accesses;
695 unsigned int age;
696 };
697
damon_sysfs_weights_alloc(unsigned int sz,unsigned int nr_accesses,unsigned int age)698 static struct damon_sysfs_weights *damon_sysfs_weights_alloc(unsigned int sz,
699 unsigned int nr_accesses, unsigned int age)
700 {
701 struct damon_sysfs_weights *weights = kmalloc(sizeof(*weights),
702 GFP_KERNEL);
703
704 if (!weights)
705 return NULL;
706 weights->kobj = (struct kobject){};
707 weights->sz = sz;
708 weights->nr_accesses = nr_accesses;
709 weights->age = age;
710 return weights;
711 }
712
sz_permil_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)713 static ssize_t sz_permil_show(struct kobject *kobj,
714 struct kobj_attribute *attr, char *buf)
715 {
716 struct damon_sysfs_weights *weights = container_of(kobj,
717 struct damon_sysfs_weights, kobj);
718
719 return sysfs_emit(buf, "%u\n", weights->sz);
720 }
721
sz_permil_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t count)722 static ssize_t sz_permil_store(struct kobject *kobj,
723 struct kobj_attribute *attr, const char *buf, size_t count)
724 {
725 struct damon_sysfs_weights *weights = container_of(kobj,
726 struct damon_sysfs_weights, kobj);
727 int err = kstrtouint(buf, 0, &weights->sz);
728
729 return err ? err : count;
730 }
731
nr_accesses_permil_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)732 static ssize_t nr_accesses_permil_show(struct kobject *kobj,
733 struct kobj_attribute *attr, char *buf)
734 {
735 struct damon_sysfs_weights *weights = container_of(kobj,
736 struct damon_sysfs_weights, kobj);
737
738 return sysfs_emit(buf, "%u\n", weights->nr_accesses);
739 }
740
nr_accesses_permil_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t count)741 static ssize_t nr_accesses_permil_store(struct kobject *kobj,
742 struct kobj_attribute *attr, const char *buf, size_t count)
743 {
744 struct damon_sysfs_weights *weights = container_of(kobj,
745 struct damon_sysfs_weights, kobj);
746 int err = kstrtouint(buf, 0, &weights->nr_accesses);
747
748 return err ? err : count;
749 }
750
age_permil_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)751 static ssize_t age_permil_show(struct kobject *kobj,
752 struct kobj_attribute *attr, char *buf)
753 {
754 struct damon_sysfs_weights *weights = container_of(kobj,
755 struct damon_sysfs_weights, kobj);
756
757 return sysfs_emit(buf, "%u\n", weights->age);
758 }
759
age_permil_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t count)760 static ssize_t age_permil_store(struct kobject *kobj,
761 struct kobj_attribute *attr, const char *buf, size_t count)
762 {
763 struct damon_sysfs_weights *weights = container_of(kobj,
764 struct damon_sysfs_weights, kobj);
765 int err = kstrtouint(buf, 0, &weights->age);
766
767 return err ? err : count;
768 }
769
damon_sysfs_weights_release(struct kobject * kobj)770 static void damon_sysfs_weights_release(struct kobject *kobj)
771 {
772 kfree(container_of(kobj, struct damon_sysfs_weights, kobj));
773 }
774
775 static struct kobj_attribute damon_sysfs_weights_sz_attr =
776 __ATTR_RW_MODE(sz_permil, 0600);
777
778 static struct kobj_attribute damon_sysfs_weights_nr_accesses_attr =
779 __ATTR_RW_MODE(nr_accesses_permil, 0600);
780
781 static struct kobj_attribute damon_sysfs_weights_age_attr =
782 __ATTR_RW_MODE(age_permil, 0600);
783
784 static struct attribute *damon_sysfs_weights_attrs[] = {
785 &damon_sysfs_weights_sz_attr.attr,
786 &damon_sysfs_weights_nr_accesses_attr.attr,
787 &damon_sysfs_weights_age_attr.attr,
788 NULL,
789 };
790 ATTRIBUTE_GROUPS(damon_sysfs_weights);
791
792 static const struct kobj_type damon_sysfs_weights_ktype = {
793 .release = damon_sysfs_weights_release,
794 .sysfs_ops = &kobj_sysfs_ops,
795 .default_groups = damon_sysfs_weights_groups,
796 };
797
798 /*
799 * quotas directory
800 */
801
802 struct damon_sysfs_quotas {
803 struct kobject kobj;
804 struct damon_sysfs_weights *weights;
805 unsigned long ms;
806 unsigned long sz;
807 unsigned long reset_interval_ms;
808 };
809
damon_sysfs_quotas_alloc(void)810 static struct damon_sysfs_quotas *damon_sysfs_quotas_alloc(void)
811 {
812 return kzalloc(sizeof(struct damon_sysfs_quotas), GFP_KERNEL);
813 }
814
damon_sysfs_quotas_add_dirs(struct damon_sysfs_quotas * quotas)815 static int damon_sysfs_quotas_add_dirs(struct damon_sysfs_quotas *quotas)
816 {
817 struct damon_sysfs_weights *weights;
818 int err;
819
820 weights = damon_sysfs_weights_alloc(0, 0, 0);
821 if (!weights)
822 return -ENOMEM;
823
824 err = kobject_init_and_add(&weights->kobj, &damon_sysfs_weights_ktype,
825 "as->kobj, "weights");
826 if (err)
827 kobject_put(&weights->kobj);
828 else
829 quotas->weights = weights;
830 return err;
831 }
832
damon_sysfs_quotas_rm_dirs(struct damon_sysfs_quotas * quotas)833 static void damon_sysfs_quotas_rm_dirs(struct damon_sysfs_quotas *quotas)
834 {
835 kobject_put("as->weights->kobj);
836 }
837
ms_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)838 static ssize_t ms_show(struct kobject *kobj, struct kobj_attribute *attr,
839 char *buf)
840 {
841 struct damon_sysfs_quotas *quotas = container_of(kobj,
842 struct damon_sysfs_quotas, kobj);
843
844 return sysfs_emit(buf, "%lu\n", quotas->ms);
845 }
846
ms_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t count)847 static ssize_t ms_store(struct kobject *kobj, struct kobj_attribute *attr,
848 const char *buf, size_t count)
849 {
850 struct damon_sysfs_quotas *quotas = container_of(kobj,
851 struct damon_sysfs_quotas, kobj);
852 int err = kstrtoul(buf, 0, "as->ms);
853
854 if (err)
855 return -EINVAL;
856 return count;
857 }
858
bytes_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)859 static ssize_t bytes_show(struct kobject *kobj, struct kobj_attribute *attr,
860 char *buf)
861 {
862 struct damon_sysfs_quotas *quotas = container_of(kobj,
863 struct damon_sysfs_quotas, kobj);
864
865 return sysfs_emit(buf, "%lu\n", quotas->sz);
866 }
867
bytes_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t count)868 static ssize_t bytes_store(struct kobject *kobj,
869 struct kobj_attribute *attr, const char *buf, size_t count)
870 {
871 struct damon_sysfs_quotas *quotas = container_of(kobj,
872 struct damon_sysfs_quotas, kobj);
873 int err = kstrtoul(buf, 0, "as->sz);
874
875 if (err)
876 return -EINVAL;
877 return count;
878 }
879
reset_interval_ms_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)880 static ssize_t reset_interval_ms_show(struct kobject *kobj,
881 struct kobj_attribute *attr, char *buf)
882 {
883 struct damon_sysfs_quotas *quotas = container_of(kobj,
884 struct damon_sysfs_quotas, kobj);
885
886 return sysfs_emit(buf, "%lu\n", quotas->reset_interval_ms);
887 }
888
reset_interval_ms_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t count)889 static ssize_t reset_interval_ms_store(struct kobject *kobj,
890 struct kobj_attribute *attr, const char *buf, size_t count)
891 {
892 struct damon_sysfs_quotas *quotas = container_of(kobj,
893 struct damon_sysfs_quotas, kobj);
894 int err = kstrtoul(buf, 0, "as->reset_interval_ms);
895
896 if (err)
897 return -EINVAL;
898 return count;
899 }
900
damon_sysfs_quotas_release(struct kobject * kobj)901 static void damon_sysfs_quotas_release(struct kobject *kobj)
902 {
903 kfree(container_of(kobj, struct damon_sysfs_quotas, kobj));
904 }
905
906 static struct kobj_attribute damon_sysfs_quotas_ms_attr =
907 __ATTR_RW_MODE(ms, 0600);
908
909 static struct kobj_attribute damon_sysfs_quotas_sz_attr =
910 __ATTR_RW_MODE(bytes, 0600);
911
912 static struct kobj_attribute damon_sysfs_quotas_reset_interval_ms_attr =
913 __ATTR_RW_MODE(reset_interval_ms, 0600);
914
915 static struct attribute *damon_sysfs_quotas_attrs[] = {
916 &damon_sysfs_quotas_ms_attr.attr,
917 &damon_sysfs_quotas_sz_attr.attr,
918 &damon_sysfs_quotas_reset_interval_ms_attr.attr,
919 NULL,
920 };
921 ATTRIBUTE_GROUPS(damon_sysfs_quotas);
922
923 static const struct kobj_type damon_sysfs_quotas_ktype = {
924 .release = damon_sysfs_quotas_release,
925 .sysfs_ops = &kobj_sysfs_ops,
926 .default_groups = damon_sysfs_quotas_groups,
927 };
928
929 /*
930 * access_pattern directory
931 */
932
933 struct damon_sysfs_access_pattern {
934 struct kobject kobj;
935 struct damon_sysfs_ul_range *sz;
936 struct damon_sysfs_ul_range *nr_accesses;
937 struct damon_sysfs_ul_range *age;
938 };
939
940 static
damon_sysfs_access_pattern_alloc(void)941 struct damon_sysfs_access_pattern *damon_sysfs_access_pattern_alloc(void)
942 {
943 struct damon_sysfs_access_pattern *access_pattern =
944 kmalloc(sizeof(*access_pattern), GFP_KERNEL);
945
946 if (!access_pattern)
947 return NULL;
948 access_pattern->kobj = (struct kobject){};
949 return access_pattern;
950 }
951
damon_sysfs_access_pattern_add_range_dir(struct damon_sysfs_access_pattern * access_pattern,struct damon_sysfs_ul_range ** range_dir_ptr,char * name)952 static int damon_sysfs_access_pattern_add_range_dir(
953 struct damon_sysfs_access_pattern *access_pattern,
954 struct damon_sysfs_ul_range **range_dir_ptr,
955 char *name)
956 {
957 struct damon_sysfs_ul_range *range = damon_sysfs_ul_range_alloc(0, 0);
958 int err;
959
960 if (!range)
961 return -ENOMEM;
962 err = kobject_init_and_add(&range->kobj, &damon_sysfs_ul_range_ktype,
963 &access_pattern->kobj, name);
964 if (err)
965 kobject_put(&range->kobj);
966 else
967 *range_dir_ptr = range;
968 return err;
969 }
970
damon_sysfs_access_pattern_add_dirs(struct damon_sysfs_access_pattern * access_pattern)971 static int damon_sysfs_access_pattern_add_dirs(
972 struct damon_sysfs_access_pattern *access_pattern)
973 {
974 int err;
975
976 err = damon_sysfs_access_pattern_add_range_dir(access_pattern,
977 &access_pattern->sz, "sz");
978 if (err)
979 goto put_sz_out;
980
981 err = damon_sysfs_access_pattern_add_range_dir(access_pattern,
982 &access_pattern->nr_accesses, "nr_accesses");
983 if (err)
984 goto put_nr_accesses_sz_out;
985
986 err = damon_sysfs_access_pattern_add_range_dir(access_pattern,
987 &access_pattern->age, "age");
988 if (err)
989 goto put_age_nr_accesses_sz_out;
990 return 0;
991
992 put_age_nr_accesses_sz_out:
993 kobject_put(&access_pattern->age->kobj);
994 access_pattern->age = NULL;
995 put_nr_accesses_sz_out:
996 kobject_put(&access_pattern->nr_accesses->kobj);
997 access_pattern->nr_accesses = NULL;
998 put_sz_out:
999 kobject_put(&access_pattern->sz->kobj);
1000 access_pattern->sz = NULL;
1001 return err;
1002 }
1003
damon_sysfs_access_pattern_rm_dirs(struct damon_sysfs_access_pattern * access_pattern)1004 static void damon_sysfs_access_pattern_rm_dirs(
1005 struct damon_sysfs_access_pattern *access_pattern)
1006 {
1007 kobject_put(&access_pattern->sz->kobj);
1008 kobject_put(&access_pattern->nr_accesses->kobj);
1009 kobject_put(&access_pattern->age->kobj);
1010 }
1011
damon_sysfs_access_pattern_release(struct kobject * kobj)1012 static void damon_sysfs_access_pattern_release(struct kobject *kobj)
1013 {
1014 kfree(container_of(kobj, struct damon_sysfs_access_pattern, kobj));
1015 }
1016
1017 static struct attribute *damon_sysfs_access_pattern_attrs[] = {
1018 NULL,
1019 };
1020 ATTRIBUTE_GROUPS(damon_sysfs_access_pattern);
1021
1022 static const struct kobj_type damon_sysfs_access_pattern_ktype = {
1023 .release = damon_sysfs_access_pattern_release,
1024 .sysfs_ops = &kobj_sysfs_ops,
1025 .default_groups = damon_sysfs_access_pattern_groups,
1026 };
1027
1028 /*
1029 * scheme directory
1030 */
1031
1032 struct damon_sysfs_scheme {
1033 struct kobject kobj;
1034 enum damos_action action;
1035 struct damon_sysfs_access_pattern *access_pattern;
1036 struct damon_sysfs_quotas *quotas;
1037 struct damon_sysfs_watermarks *watermarks;
1038 struct damon_sysfs_scheme_filters *filters;
1039 struct damon_sysfs_stats *stats;
1040 struct damon_sysfs_scheme_regions *tried_regions;
1041 };
1042
1043 /* This should match with enum damos_action */
1044 static const char * const damon_sysfs_damos_action_strs[] = {
1045 "willneed",
1046 "cold",
1047 "pageout",
1048 "hugepage",
1049 "nohugepage",
1050 "lru_prio",
1051 "lru_deprio",
1052 "stat",
1053 };
1054
damon_sysfs_scheme_alloc(enum damos_action action)1055 static struct damon_sysfs_scheme *damon_sysfs_scheme_alloc(
1056 enum damos_action action)
1057 {
1058 struct damon_sysfs_scheme *scheme = kmalloc(sizeof(*scheme),
1059 GFP_KERNEL);
1060
1061 if (!scheme)
1062 return NULL;
1063 scheme->kobj = (struct kobject){};
1064 scheme->action = action;
1065 return scheme;
1066 }
1067
damon_sysfs_scheme_set_access_pattern(struct damon_sysfs_scheme * scheme)1068 static int damon_sysfs_scheme_set_access_pattern(
1069 struct damon_sysfs_scheme *scheme)
1070 {
1071 struct damon_sysfs_access_pattern *access_pattern;
1072 int err;
1073
1074 access_pattern = damon_sysfs_access_pattern_alloc();
1075 if (!access_pattern)
1076 return -ENOMEM;
1077 err = kobject_init_and_add(&access_pattern->kobj,
1078 &damon_sysfs_access_pattern_ktype, &scheme->kobj,
1079 "access_pattern");
1080 if (err)
1081 goto out;
1082 err = damon_sysfs_access_pattern_add_dirs(access_pattern);
1083 if (err)
1084 goto out;
1085 scheme->access_pattern = access_pattern;
1086 return 0;
1087
1088 out:
1089 kobject_put(&access_pattern->kobj);
1090 return err;
1091 }
1092
damon_sysfs_scheme_set_quotas(struct damon_sysfs_scheme * scheme)1093 static int damon_sysfs_scheme_set_quotas(struct damon_sysfs_scheme *scheme)
1094 {
1095 struct damon_sysfs_quotas *quotas = damon_sysfs_quotas_alloc();
1096 int err;
1097
1098 if (!quotas)
1099 return -ENOMEM;
1100 err = kobject_init_and_add("as->kobj, &damon_sysfs_quotas_ktype,
1101 &scheme->kobj, "quotas");
1102 if (err)
1103 goto out;
1104 err = damon_sysfs_quotas_add_dirs(quotas);
1105 if (err)
1106 goto out;
1107 scheme->quotas = quotas;
1108 return 0;
1109
1110 out:
1111 kobject_put("as->kobj);
1112 return err;
1113 }
1114
damon_sysfs_scheme_set_watermarks(struct damon_sysfs_scheme * scheme)1115 static int damon_sysfs_scheme_set_watermarks(struct damon_sysfs_scheme *scheme)
1116 {
1117 struct damon_sysfs_watermarks *watermarks =
1118 damon_sysfs_watermarks_alloc(DAMOS_WMARK_NONE, 0, 0, 0, 0);
1119 int err;
1120
1121 if (!watermarks)
1122 return -ENOMEM;
1123 err = kobject_init_and_add(&watermarks->kobj,
1124 &damon_sysfs_watermarks_ktype, &scheme->kobj,
1125 "watermarks");
1126 if (err)
1127 kobject_put(&watermarks->kobj);
1128 else
1129 scheme->watermarks = watermarks;
1130 return err;
1131 }
1132
damon_sysfs_scheme_set_filters(struct damon_sysfs_scheme * scheme)1133 static int damon_sysfs_scheme_set_filters(struct damon_sysfs_scheme *scheme)
1134 {
1135 struct damon_sysfs_scheme_filters *filters =
1136 damon_sysfs_scheme_filters_alloc();
1137 int err;
1138
1139 if (!filters)
1140 return -ENOMEM;
1141 err = kobject_init_and_add(&filters->kobj,
1142 &damon_sysfs_scheme_filters_ktype, &scheme->kobj,
1143 "filters");
1144 if (err)
1145 kobject_put(&filters->kobj);
1146 else
1147 scheme->filters = filters;
1148 return err;
1149 }
1150
damon_sysfs_scheme_set_stats(struct damon_sysfs_scheme * scheme)1151 static int damon_sysfs_scheme_set_stats(struct damon_sysfs_scheme *scheme)
1152 {
1153 struct damon_sysfs_stats *stats = damon_sysfs_stats_alloc();
1154 int err;
1155
1156 if (!stats)
1157 return -ENOMEM;
1158 err = kobject_init_and_add(&stats->kobj, &damon_sysfs_stats_ktype,
1159 &scheme->kobj, "stats");
1160 if (err)
1161 kobject_put(&stats->kobj);
1162 else
1163 scheme->stats = stats;
1164 return err;
1165 }
1166
damon_sysfs_scheme_set_tried_regions(struct damon_sysfs_scheme * scheme)1167 static int damon_sysfs_scheme_set_tried_regions(
1168 struct damon_sysfs_scheme *scheme)
1169 {
1170 struct damon_sysfs_scheme_regions *tried_regions =
1171 damon_sysfs_scheme_regions_alloc();
1172 int err;
1173
1174 if (!tried_regions)
1175 return -ENOMEM;
1176 err = kobject_init_and_add(&tried_regions->kobj,
1177 &damon_sysfs_scheme_regions_ktype, &scheme->kobj,
1178 "tried_regions");
1179 if (err)
1180 kobject_put(&tried_regions->kobj);
1181 else
1182 scheme->tried_regions = tried_regions;
1183 return err;
1184 }
1185
damon_sysfs_scheme_add_dirs(struct damon_sysfs_scheme * scheme)1186 static int damon_sysfs_scheme_add_dirs(struct damon_sysfs_scheme *scheme)
1187 {
1188 int err;
1189
1190 err = damon_sysfs_scheme_set_access_pattern(scheme);
1191 if (err)
1192 return err;
1193 err = damon_sysfs_scheme_set_quotas(scheme);
1194 if (err)
1195 goto put_access_pattern_out;
1196 err = damon_sysfs_scheme_set_watermarks(scheme);
1197 if (err)
1198 goto put_quotas_access_pattern_out;
1199 err = damon_sysfs_scheme_set_filters(scheme);
1200 if (err)
1201 goto put_watermarks_quotas_access_pattern_out;
1202 err = damon_sysfs_scheme_set_stats(scheme);
1203 if (err)
1204 goto put_filters_watermarks_quotas_access_pattern_out;
1205 err = damon_sysfs_scheme_set_tried_regions(scheme);
1206 if (err)
1207 goto put_tried_regions_out;
1208 return 0;
1209
1210 put_tried_regions_out:
1211 kobject_put(&scheme->tried_regions->kobj);
1212 scheme->tried_regions = NULL;
1213 put_filters_watermarks_quotas_access_pattern_out:
1214 kobject_put(&scheme->filters->kobj);
1215 scheme->filters = NULL;
1216 put_watermarks_quotas_access_pattern_out:
1217 kobject_put(&scheme->watermarks->kobj);
1218 scheme->watermarks = NULL;
1219 put_quotas_access_pattern_out:
1220 kobject_put(&scheme->quotas->kobj);
1221 scheme->quotas = NULL;
1222 put_access_pattern_out:
1223 kobject_put(&scheme->access_pattern->kobj);
1224 scheme->access_pattern = NULL;
1225 return err;
1226 }
1227
damon_sysfs_scheme_rm_dirs(struct damon_sysfs_scheme * scheme)1228 static void damon_sysfs_scheme_rm_dirs(struct damon_sysfs_scheme *scheme)
1229 {
1230 damon_sysfs_access_pattern_rm_dirs(scheme->access_pattern);
1231 kobject_put(&scheme->access_pattern->kobj);
1232 damon_sysfs_quotas_rm_dirs(scheme->quotas);
1233 kobject_put(&scheme->quotas->kobj);
1234 kobject_put(&scheme->watermarks->kobj);
1235 damon_sysfs_scheme_filters_rm_dirs(scheme->filters);
1236 kobject_put(&scheme->filters->kobj);
1237 kobject_put(&scheme->stats->kobj);
1238 damon_sysfs_scheme_regions_rm_dirs(scheme->tried_regions);
1239 kobject_put(&scheme->tried_regions->kobj);
1240 }
1241
action_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)1242 static ssize_t action_show(struct kobject *kobj, struct kobj_attribute *attr,
1243 char *buf)
1244 {
1245 struct damon_sysfs_scheme *scheme = container_of(kobj,
1246 struct damon_sysfs_scheme, kobj);
1247
1248 return sysfs_emit(buf, "%s\n",
1249 damon_sysfs_damos_action_strs[scheme->action]);
1250 }
1251
action_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t count)1252 static ssize_t action_store(struct kobject *kobj, struct kobj_attribute *attr,
1253 const char *buf, size_t count)
1254 {
1255 struct damon_sysfs_scheme *scheme = container_of(kobj,
1256 struct damon_sysfs_scheme, kobj);
1257 enum damos_action action;
1258
1259 for (action = 0; action < NR_DAMOS_ACTIONS; action++) {
1260 if (sysfs_streq(buf, damon_sysfs_damos_action_strs[action])) {
1261 scheme->action = action;
1262 return count;
1263 }
1264 }
1265 return -EINVAL;
1266 }
1267
damon_sysfs_scheme_release(struct kobject * kobj)1268 static void damon_sysfs_scheme_release(struct kobject *kobj)
1269 {
1270 kfree(container_of(kobj, struct damon_sysfs_scheme, kobj));
1271 }
1272
1273 static struct kobj_attribute damon_sysfs_scheme_action_attr =
1274 __ATTR_RW_MODE(action, 0600);
1275
1276 static struct attribute *damon_sysfs_scheme_attrs[] = {
1277 &damon_sysfs_scheme_action_attr.attr,
1278 NULL,
1279 };
1280 ATTRIBUTE_GROUPS(damon_sysfs_scheme);
1281
1282 static const struct kobj_type damon_sysfs_scheme_ktype = {
1283 .release = damon_sysfs_scheme_release,
1284 .sysfs_ops = &kobj_sysfs_ops,
1285 .default_groups = damon_sysfs_scheme_groups,
1286 };
1287
1288 /*
1289 * schemes directory
1290 */
1291
damon_sysfs_schemes_alloc(void)1292 struct damon_sysfs_schemes *damon_sysfs_schemes_alloc(void)
1293 {
1294 return kzalloc(sizeof(struct damon_sysfs_schemes), GFP_KERNEL);
1295 }
1296
damon_sysfs_schemes_rm_dirs(struct damon_sysfs_schemes * schemes)1297 void damon_sysfs_schemes_rm_dirs(struct damon_sysfs_schemes *schemes)
1298 {
1299 struct damon_sysfs_scheme **schemes_arr = schemes->schemes_arr;
1300 int i;
1301
1302 for (i = 0; i < schemes->nr; i++) {
1303 damon_sysfs_scheme_rm_dirs(schemes_arr[i]);
1304 kobject_put(&schemes_arr[i]->kobj);
1305 }
1306 schemes->nr = 0;
1307 kfree(schemes_arr);
1308 schemes->schemes_arr = NULL;
1309 }
1310
damon_sysfs_schemes_add_dirs(struct damon_sysfs_schemes * schemes,int nr_schemes)1311 static int damon_sysfs_schemes_add_dirs(struct damon_sysfs_schemes *schemes,
1312 int nr_schemes)
1313 {
1314 struct damon_sysfs_scheme **schemes_arr, *scheme;
1315 int err, i;
1316
1317 damon_sysfs_schemes_rm_dirs(schemes);
1318 if (!nr_schemes)
1319 return 0;
1320
1321 schemes_arr = kmalloc_array(nr_schemes, sizeof(*schemes_arr),
1322 GFP_KERNEL | __GFP_NOWARN);
1323 if (!schemes_arr)
1324 return -ENOMEM;
1325 schemes->schemes_arr = schemes_arr;
1326
1327 for (i = 0; i < nr_schemes; i++) {
1328 scheme = damon_sysfs_scheme_alloc(DAMOS_STAT);
1329 if (!scheme) {
1330 damon_sysfs_schemes_rm_dirs(schemes);
1331 return -ENOMEM;
1332 }
1333
1334 err = kobject_init_and_add(&scheme->kobj,
1335 &damon_sysfs_scheme_ktype, &schemes->kobj,
1336 "%d", i);
1337 if (err)
1338 goto out;
1339 err = damon_sysfs_scheme_add_dirs(scheme);
1340 if (err)
1341 goto out;
1342
1343 schemes_arr[i] = scheme;
1344 schemes->nr++;
1345 }
1346 return 0;
1347
1348 out:
1349 damon_sysfs_schemes_rm_dirs(schemes);
1350 kobject_put(&scheme->kobj);
1351 return err;
1352 }
1353
nr_schemes_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)1354 static ssize_t nr_schemes_show(struct kobject *kobj,
1355 struct kobj_attribute *attr, char *buf)
1356 {
1357 struct damon_sysfs_schemes *schemes = container_of(kobj,
1358 struct damon_sysfs_schemes, kobj);
1359
1360 return sysfs_emit(buf, "%d\n", schemes->nr);
1361 }
1362
nr_schemes_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t count)1363 static ssize_t nr_schemes_store(struct kobject *kobj,
1364 struct kobj_attribute *attr, const char *buf, size_t count)
1365 {
1366 struct damon_sysfs_schemes *schemes;
1367 int nr, err = kstrtoint(buf, 0, &nr);
1368
1369 if (err)
1370 return err;
1371 if (nr < 0)
1372 return -EINVAL;
1373
1374 schemes = container_of(kobj, struct damon_sysfs_schemes, kobj);
1375
1376 if (!mutex_trylock(&damon_sysfs_lock))
1377 return -EBUSY;
1378 err = damon_sysfs_schemes_add_dirs(schemes, nr);
1379 mutex_unlock(&damon_sysfs_lock);
1380 if (err)
1381 return err;
1382 return count;
1383 }
1384
damon_sysfs_schemes_release(struct kobject * kobj)1385 static void damon_sysfs_schemes_release(struct kobject *kobj)
1386 {
1387 kfree(container_of(kobj, struct damon_sysfs_schemes, kobj));
1388 }
1389
1390 static struct kobj_attribute damon_sysfs_schemes_nr_attr =
1391 __ATTR_RW_MODE(nr_schemes, 0600);
1392
1393 static struct attribute *damon_sysfs_schemes_attrs[] = {
1394 &damon_sysfs_schemes_nr_attr.attr,
1395 NULL,
1396 };
1397 ATTRIBUTE_GROUPS(damon_sysfs_schemes);
1398
1399 const struct kobj_type damon_sysfs_schemes_ktype = {
1400 .release = damon_sysfs_schemes_release,
1401 .sysfs_ops = &kobj_sysfs_ops,
1402 .default_groups = damon_sysfs_schemes_groups,
1403 };
1404
damon_sysfs_memcg_path_eq(struct mem_cgroup * memcg,char * memcg_path_buf,char * path)1405 static bool damon_sysfs_memcg_path_eq(struct mem_cgroup *memcg,
1406 char *memcg_path_buf, char *path)
1407 {
1408 #ifdef CONFIG_MEMCG
1409 cgroup_path(memcg->css.cgroup, memcg_path_buf, PATH_MAX);
1410 if (sysfs_streq(memcg_path_buf, path))
1411 return true;
1412 #endif /* CONFIG_MEMCG */
1413 return false;
1414 }
1415
damon_sysfs_memcg_path_to_id(char * memcg_path,unsigned short * id)1416 static int damon_sysfs_memcg_path_to_id(char *memcg_path, unsigned short *id)
1417 {
1418 struct mem_cgroup *memcg;
1419 char *path;
1420 bool found = false;
1421
1422 if (!memcg_path)
1423 return -EINVAL;
1424
1425 path = kmalloc(sizeof(*path) * PATH_MAX, GFP_KERNEL);
1426 if (!path)
1427 return -ENOMEM;
1428
1429 for (memcg = mem_cgroup_iter(NULL, NULL, NULL); memcg;
1430 memcg = mem_cgroup_iter(NULL, memcg, NULL)) {
1431 /* skip removed memcg */
1432 if (!mem_cgroup_id(memcg))
1433 continue;
1434 if (damon_sysfs_memcg_path_eq(memcg, path, memcg_path)) {
1435 *id = mem_cgroup_id(memcg);
1436 found = true;
1437 break;
1438 }
1439 }
1440
1441 kfree(path);
1442 return found ? 0 : -EINVAL;
1443 }
1444
damon_sysfs_set_scheme_filters(struct damos * scheme,struct damon_sysfs_scheme_filters * sysfs_filters)1445 static int damon_sysfs_set_scheme_filters(struct damos *scheme,
1446 struct damon_sysfs_scheme_filters *sysfs_filters)
1447 {
1448 int i;
1449 struct damos_filter *filter, *next;
1450
1451 damos_for_each_filter_safe(filter, next, scheme)
1452 damos_destroy_filter(filter);
1453
1454 for (i = 0; i < sysfs_filters->nr; i++) {
1455 struct damon_sysfs_scheme_filter *sysfs_filter =
1456 sysfs_filters->filters_arr[i];
1457 struct damos_filter *filter =
1458 damos_new_filter(sysfs_filter->type,
1459 sysfs_filter->matching);
1460 int err;
1461
1462 if (!filter)
1463 return -ENOMEM;
1464 if (filter->type == DAMOS_FILTER_TYPE_MEMCG) {
1465 err = damon_sysfs_memcg_path_to_id(
1466 sysfs_filter->memcg_path,
1467 &filter->memcg_id);
1468 if (err) {
1469 damos_destroy_filter(filter);
1470 return err;
1471 }
1472 }
1473 damos_add_filter(scheme, filter);
1474 }
1475 return 0;
1476 }
1477
damon_sysfs_mk_scheme(struct damon_sysfs_scheme * sysfs_scheme)1478 static struct damos *damon_sysfs_mk_scheme(
1479 struct damon_sysfs_scheme *sysfs_scheme)
1480 {
1481 struct damon_sysfs_access_pattern *access_pattern =
1482 sysfs_scheme->access_pattern;
1483 struct damon_sysfs_quotas *sysfs_quotas = sysfs_scheme->quotas;
1484 struct damon_sysfs_weights *sysfs_weights = sysfs_quotas->weights;
1485 struct damon_sysfs_watermarks *sysfs_wmarks = sysfs_scheme->watermarks;
1486 struct damon_sysfs_scheme_filters *sysfs_filters =
1487 sysfs_scheme->filters;
1488 struct damos *scheme;
1489 int err;
1490
1491 struct damos_access_pattern pattern = {
1492 .min_sz_region = access_pattern->sz->min,
1493 .max_sz_region = access_pattern->sz->max,
1494 .min_nr_accesses = access_pattern->nr_accesses->min,
1495 .max_nr_accesses = access_pattern->nr_accesses->max,
1496 .min_age_region = access_pattern->age->min,
1497 .max_age_region = access_pattern->age->max,
1498 };
1499 struct damos_quota quota = {
1500 .ms = sysfs_quotas->ms,
1501 .sz = sysfs_quotas->sz,
1502 .reset_interval = sysfs_quotas->reset_interval_ms,
1503 .weight_sz = sysfs_weights->sz,
1504 .weight_nr_accesses = sysfs_weights->nr_accesses,
1505 .weight_age = sysfs_weights->age,
1506 };
1507 struct damos_watermarks wmarks = {
1508 .metric = sysfs_wmarks->metric,
1509 .interval = sysfs_wmarks->interval_us,
1510 .high = sysfs_wmarks->high,
1511 .mid = sysfs_wmarks->mid,
1512 .low = sysfs_wmarks->low,
1513 };
1514
1515 scheme = damon_new_scheme(&pattern, sysfs_scheme->action, "a,
1516 &wmarks);
1517 if (!scheme)
1518 return NULL;
1519
1520 err = damon_sysfs_set_scheme_filters(scheme, sysfs_filters);
1521 if (err) {
1522 damon_destroy_scheme(scheme);
1523 return NULL;
1524 }
1525 return scheme;
1526 }
1527
damon_sysfs_update_scheme(struct damos * scheme,struct damon_sysfs_scheme * sysfs_scheme)1528 static void damon_sysfs_update_scheme(struct damos *scheme,
1529 struct damon_sysfs_scheme *sysfs_scheme)
1530 {
1531 struct damon_sysfs_access_pattern *access_pattern =
1532 sysfs_scheme->access_pattern;
1533 struct damon_sysfs_quotas *sysfs_quotas = sysfs_scheme->quotas;
1534 struct damon_sysfs_weights *sysfs_weights = sysfs_quotas->weights;
1535 struct damon_sysfs_watermarks *sysfs_wmarks = sysfs_scheme->watermarks;
1536 int err;
1537
1538 scheme->pattern.min_sz_region = access_pattern->sz->min;
1539 scheme->pattern.max_sz_region = access_pattern->sz->max;
1540 scheme->pattern.min_nr_accesses = access_pattern->nr_accesses->min;
1541 scheme->pattern.max_nr_accesses = access_pattern->nr_accesses->max;
1542 scheme->pattern.min_age_region = access_pattern->age->min;
1543 scheme->pattern.max_age_region = access_pattern->age->max;
1544
1545 scheme->action = sysfs_scheme->action;
1546
1547 scheme->quota.ms = sysfs_quotas->ms;
1548 scheme->quota.sz = sysfs_quotas->sz;
1549 scheme->quota.reset_interval = sysfs_quotas->reset_interval_ms;
1550 scheme->quota.weight_sz = sysfs_weights->sz;
1551 scheme->quota.weight_nr_accesses = sysfs_weights->nr_accesses;
1552 scheme->quota.weight_age = sysfs_weights->age;
1553
1554 scheme->wmarks.metric = sysfs_wmarks->metric;
1555 scheme->wmarks.interval = sysfs_wmarks->interval_us;
1556 scheme->wmarks.high = sysfs_wmarks->high;
1557 scheme->wmarks.mid = sysfs_wmarks->mid;
1558 scheme->wmarks.low = sysfs_wmarks->low;
1559
1560 err = damon_sysfs_set_scheme_filters(scheme, sysfs_scheme->filters);
1561 if (err)
1562 damon_destroy_scheme(scheme);
1563 }
1564
damon_sysfs_set_schemes(struct damon_ctx * ctx,struct damon_sysfs_schemes * sysfs_schemes)1565 int damon_sysfs_set_schemes(struct damon_ctx *ctx,
1566 struct damon_sysfs_schemes *sysfs_schemes)
1567 {
1568 struct damos *scheme, *next;
1569 int i = 0;
1570
1571 damon_for_each_scheme_safe(scheme, next, ctx) {
1572 if (i < sysfs_schemes->nr)
1573 damon_sysfs_update_scheme(scheme,
1574 sysfs_schemes->schemes_arr[i]);
1575 else
1576 damon_destroy_scheme(scheme);
1577 i++;
1578 }
1579
1580 for (; i < sysfs_schemes->nr; i++) {
1581 struct damos *scheme, *next;
1582
1583 scheme = damon_sysfs_mk_scheme(sysfs_schemes->schemes_arr[i]);
1584 if (!scheme) {
1585 damon_for_each_scheme_safe(scheme, next, ctx)
1586 damon_destroy_scheme(scheme);
1587 return -ENOMEM;
1588 }
1589 damon_add_scheme(ctx, scheme);
1590 }
1591 return 0;
1592 }
1593
damon_sysfs_schemes_update_stats(struct damon_sysfs_schemes * sysfs_schemes,struct damon_ctx * ctx)1594 void damon_sysfs_schemes_update_stats(
1595 struct damon_sysfs_schemes *sysfs_schemes,
1596 struct damon_ctx *ctx)
1597 {
1598 struct damos *scheme;
1599 int schemes_idx = 0;
1600
1601 damon_for_each_scheme(scheme, ctx) {
1602 struct damon_sysfs_stats *sysfs_stats;
1603
1604 /* user could have removed the scheme sysfs dir */
1605 if (schemes_idx >= sysfs_schemes->nr)
1606 break;
1607
1608 sysfs_stats = sysfs_schemes->schemes_arr[schemes_idx++]->stats;
1609 sysfs_stats->nr_tried = scheme->stat.nr_tried;
1610 sysfs_stats->sz_tried = scheme->stat.sz_tried;
1611 sysfs_stats->nr_applied = scheme->stat.nr_applied;
1612 sysfs_stats->sz_applied = scheme->stat.sz_applied;
1613 sysfs_stats->qt_exceeds = scheme->stat.qt_exceeds;
1614 }
1615 }
1616
1617 /*
1618 * damon_sysfs_schemes that need to update its schemes regions dir. Protected
1619 * by damon_sysfs_lock
1620 */
1621 static struct damon_sysfs_schemes *damon_sysfs_schemes_for_damos_callback;
1622 static int damon_sysfs_schemes_region_idx;
1623
1624 /*
1625 * DAMON callback that called before damos apply. While this callback is
1626 * registered, damon_sysfs_lock should be held to ensure the regions
1627 * directories exist.
1628 */
damon_sysfs_before_damos_apply(struct damon_ctx * ctx,struct damon_target * t,struct damon_region * r,struct damos * s)1629 static int damon_sysfs_before_damos_apply(struct damon_ctx *ctx,
1630 struct damon_target *t, struct damon_region *r,
1631 struct damos *s)
1632 {
1633 struct damos *scheme;
1634 struct damon_sysfs_scheme_regions *sysfs_regions;
1635 struct damon_sysfs_scheme_region *region;
1636 struct damon_sysfs_schemes *sysfs_schemes =
1637 damon_sysfs_schemes_for_damos_callback;
1638 int schemes_idx = 0;
1639
1640 damon_for_each_scheme(scheme, ctx) {
1641 if (scheme == s)
1642 break;
1643 schemes_idx++;
1644 }
1645
1646 /* user could have removed the scheme sysfs dir */
1647 if (schemes_idx >= sysfs_schemes->nr)
1648 return 0;
1649
1650 sysfs_regions = sysfs_schemes->schemes_arr[schemes_idx]->tried_regions;
1651 region = damon_sysfs_scheme_region_alloc(r);
1652 list_add_tail(®ion->list, &sysfs_regions->regions_list);
1653 sysfs_regions->nr_regions++;
1654 if (kobject_init_and_add(®ion->kobj,
1655 &damon_sysfs_scheme_region_ktype,
1656 &sysfs_regions->kobj, "%d",
1657 damon_sysfs_schemes_region_idx++)) {
1658 kobject_put(®ion->kobj);
1659 }
1660 return 0;
1661 }
1662
1663 /* Called from damon_sysfs_cmd_request_callback under damon_sysfs_lock */
damon_sysfs_schemes_clear_regions(struct damon_sysfs_schemes * sysfs_schemes,struct damon_ctx * ctx)1664 int damon_sysfs_schemes_clear_regions(
1665 struct damon_sysfs_schemes *sysfs_schemes,
1666 struct damon_ctx *ctx)
1667 {
1668 struct damos *scheme;
1669 int schemes_idx = 0;
1670
1671 damon_for_each_scheme(scheme, ctx) {
1672 struct damon_sysfs_scheme *sysfs_scheme;
1673
1674 /* user could have removed the scheme sysfs dir */
1675 if (schemes_idx >= sysfs_schemes->nr)
1676 break;
1677
1678 sysfs_scheme = sysfs_schemes->schemes_arr[schemes_idx++];
1679 damon_sysfs_scheme_regions_rm_dirs(
1680 sysfs_scheme->tried_regions);
1681 }
1682 return 0;
1683 }
1684
1685 /* Called from damon_sysfs_cmd_request_callback under damon_sysfs_lock */
damon_sysfs_schemes_update_regions_start(struct damon_sysfs_schemes * sysfs_schemes,struct damon_ctx * ctx)1686 int damon_sysfs_schemes_update_regions_start(
1687 struct damon_sysfs_schemes *sysfs_schemes,
1688 struct damon_ctx *ctx)
1689 {
1690 damon_sysfs_schemes_clear_regions(sysfs_schemes, ctx);
1691 damon_sysfs_schemes_for_damos_callback = sysfs_schemes;
1692 ctx->callback.before_damos_apply = damon_sysfs_before_damos_apply;
1693 return 0;
1694 }
1695
1696 /*
1697 * Called from damon_sysfs_cmd_request_callback under damon_sysfs_lock. Caller
1698 * should unlock damon_sysfs_lock which held before
1699 * damon_sysfs_schemes_update_regions_start()
1700 */
damon_sysfs_schemes_update_regions_stop(struct damon_ctx * ctx)1701 int damon_sysfs_schemes_update_regions_stop(struct damon_ctx *ctx)
1702 {
1703 damon_sysfs_schemes_for_damos_callback = NULL;
1704 ctx->callback.before_damos_apply = NULL;
1705 damon_sysfs_schemes_region_idx = 0;
1706 return 0;
1707 }
1708