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
damon_sysfs_ul_range_alloc(unsigned long min,unsigned long max)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
min_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)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
min_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t count)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
max_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)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
max_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t count)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
damon_sysfs_ul_range_release(struct kobject * kobj)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
damon_sysfs_memcg_path_eq(struct mem_cgroup * memcg,char * memcg_path_buf,char * path)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
damon_sysfs_memcg_path_to_id(char * memcg_path,u64 * id)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