xref: /linux/mm/damon/sysfs-common.c (revision 9d19ca5d0e8b4a3f4b2eaa14e86a25f1c93ff35b)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Common Code for DAMON Sysfs Interface
4  */
5 
6 #include <linux/slab.h>
7 
8 #include "sysfs-common.h"
9 
10 DEFINE_MUTEX(damon_sysfs_lock);
11 
12 /*
13  * unsigned long range directory
14  */
15 
16 struct damon_sysfs_ul_range *damon_sysfs_ul_range_alloc(
17 		unsigned long min,
18 		unsigned long max)
19 {
20 	struct damon_sysfs_ul_range *range = kmalloc_obj(*range);
21 
22 	if (!range)
23 		return NULL;
24 	range->kobj = (struct kobject){};
25 	range->min = min;
26 	range->max = max;
27 
28 	return range;
29 }
30 
31 static ssize_t min_show(struct kobject *kobj, struct kobj_attribute *attr,
32 		char *buf)
33 {
34 	struct damon_sysfs_ul_range *range = container_of(kobj,
35 			struct damon_sysfs_ul_range, kobj);
36 
37 	return sysfs_emit(buf, "%lu\n", range->min);
38 }
39 
40 static ssize_t min_store(struct kobject *kobj, struct kobj_attribute *attr,
41 		const char *buf, size_t count)
42 {
43 	struct damon_sysfs_ul_range *range = container_of(kobj,
44 			struct damon_sysfs_ul_range, kobj);
45 	unsigned long min;
46 	int err;
47 
48 	err = kstrtoul(buf, 0, &min);
49 	if (err)
50 		return err;
51 
52 	range->min = min;
53 	return count;
54 }
55 
56 static ssize_t max_show(struct kobject *kobj, struct kobj_attribute *attr,
57 		char *buf)
58 {
59 	struct damon_sysfs_ul_range *range = container_of(kobj,
60 			struct damon_sysfs_ul_range, kobj);
61 
62 	return sysfs_emit(buf, "%lu\n", range->max);
63 }
64 
65 static ssize_t max_store(struct kobject *kobj, struct kobj_attribute *attr,
66 		const char *buf, size_t count)
67 {
68 	struct damon_sysfs_ul_range *range = container_of(kobj,
69 			struct damon_sysfs_ul_range, kobj);
70 	unsigned long max;
71 	int err;
72 
73 	err = kstrtoul(buf, 0, &max);
74 	if (err)
75 		return err;
76 
77 	range->max = max;
78 	return count;
79 }
80 
81 void damon_sysfs_ul_range_release(struct kobject *kobj)
82 {
83 	kfree(container_of(kobj, struct damon_sysfs_ul_range, kobj));
84 }
85 
86 static struct kobj_attribute damon_sysfs_ul_range_min_attr =
87 		__ATTR_RW_MODE(min, 0600);
88 
89 static struct kobj_attribute damon_sysfs_ul_range_max_attr =
90 		__ATTR_RW_MODE(max, 0600);
91 
92 static struct attribute *damon_sysfs_ul_range_attrs[] = {
93 	&damon_sysfs_ul_range_min_attr.attr,
94 	&damon_sysfs_ul_range_max_attr.attr,
95 	NULL,
96 };
97 ATTRIBUTE_GROUPS(damon_sysfs_ul_range);
98 
99 const struct kobj_type damon_sysfs_ul_range_ktype = {
100 	.release = damon_sysfs_ul_range_release,
101 	.sysfs_ops = &kobj_sysfs_ops,
102 	.default_groups = damon_sysfs_ul_range_groups,
103 };
104 
105 
106 static bool damon_sysfs_memcg_path_eq(struct mem_cgroup *memcg,
107 		char *memcg_path_buf, char *path)
108 {
109 #ifdef CONFIG_MEMCG
110 	cgroup_path(memcg->css.cgroup, memcg_path_buf, PATH_MAX);
111 	if (sysfs_streq(memcg_path_buf, path))
112 		return true;
113 #endif /* CONFIG_MEMCG */
114 	return false;
115 }
116 
117 int damon_sysfs_memcg_path_to_id(char *memcg_path, u64 *id)
118 {
119 	struct mem_cgroup *memcg;
120 	char *path;
121 	bool found = false;
122 
123 	if (!memcg_path)
124 		return -EINVAL;
125 
126 	path = kmalloc_array(PATH_MAX, sizeof(*path), GFP_KERNEL);
127 	if (!path)
128 		return -ENOMEM;
129 
130 	for (memcg = mem_cgroup_iter(NULL, NULL, NULL); memcg;
131 			memcg = mem_cgroup_iter(NULL, memcg, NULL)) {
132 		/* skip offlined memcg */
133 		if (!mem_cgroup_online(memcg))
134 			continue;
135 		if (damon_sysfs_memcg_path_eq(memcg, path, memcg_path)) {
136 			*id = mem_cgroup_id(memcg);
137 			found = true;
138 			mem_cgroup_iter_break(NULL, memcg);
139 			break;
140 		}
141 	}
142 
143 	kfree(path);
144 	return found ? 0 : -EINVAL;
145 }
146