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