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