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