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