1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/idr.h>
3 #include <linux/slab.h>
4 #include <linux/debugfs.h>
5 #include <linux/seq_file.h>
6 #include <linux/shrinker.h>
7 #include <linux/memcontrol.h>
8
9 #include "internal.h"
10
11 /* defined in vmscan.c */
12 extern struct mutex shrinker_mutex;
13 extern struct list_head shrinker_list;
14
15 static DEFINE_IDA(shrinker_debugfs_ida);
16 static struct dentry *shrinker_debugfs_root;
17
shrinker_count_objects(struct shrinker * shrinker,struct mem_cgroup * memcg,unsigned long * count_per_node)18 static unsigned long shrinker_count_objects(struct shrinker *shrinker,
19 struct mem_cgroup *memcg,
20 unsigned long *count_per_node)
21 {
22 unsigned long nr, total = 0;
23 int nid;
24
25 for_each_node(nid) {
26 if (nid == 0 || (shrinker->flags & SHRINKER_NUMA_AWARE)) {
27 struct shrink_control sc = {
28 .gfp_mask = GFP_KERNEL,
29 .nid = nid,
30 .memcg = memcg,
31 };
32
33 nr = shrinker->count_objects(shrinker, &sc);
34 if (nr == SHRINK_EMPTY)
35 nr = 0;
36 } else {
37 nr = 0;
38 }
39
40 count_per_node[nid] = nr;
41 total += nr;
42 }
43
44 return total;
45 }
46
shrinker_debugfs_count_show(struct seq_file * m,void * v)47 static int shrinker_debugfs_count_show(struct seq_file *m, void *v)
48 {
49 struct shrinker *shrinker = m->private;
50 unsigned long *count_per_node;
51 struct mem_cgroup *memcg;
52 unsigned long total;
53 bool memcg_aware;
54 int ret = 0, nid;
55
56 count_per_node = kcalloc(nr_node_ids, sizeof(unsigned long), GFP_KERNEL);
57 if (!count_per_node)
58 return -ENOMEM;
59
60 memcg_aware = shrinker->flags & SHRINKER_MEMCG_AWARE;
61
62 memcg = mem_cgroup_iter(NULL, NULL, NULL);
63 do {
64 if (memcg && !mem_cgroup_online(memcg))
65 continue;
66
67 total = shrinker_count_objects(shrinker,
68 memcg_aware ? memcg : NULL,
69 count_per_node);
70 if (total) {
71 seq_printf(m, "%llu", mem_cgroup_id(memcg));
72 for_each_node(nid)
73 seq_printf(m, " %lu", count_per_node[nid]);
74 seq_putc(m, '\n');
75 }
76
77 if (!memcg_aware) {
78 mem_cgroup_iter_break(NULL, memcg);
79 break;
80 }
81
82 if (signal_pending(current)) {
83 mem_cgroup_iter_break(NULL, memcg);
84 ret = -EINTR;
85 break;
86 }
87 } while ((memcg = mem_cgroup_iter(NULL, memcg, NULL)) != NULL);
88
89 kfree(count_per_node);
90 return ret;
91 }
92 DEFINE_SHOW_ATTRIBUTE(shrinker_debugfs_count);
93
shrinker_debugfs_scan_open(struct inode * inode,struct file * file)94 static int shrinker_debugfs_scan_open(struct inode *inode, struct file *file)
95 {
96 file->private_data = inode->i_private;
97 return nonseekable_open(inode, file);
98 }
99
shrinker_debugfs_scan_write(struct file * file,const char __user * buf,size_t size,loff_t * pos)100 static ssize_t shrinker_debugfs_scan_write(struct file *file,
101 const char __user *buf,
102 size_t size, loff_t *pos)
103 {
104 struct shrinker *shrinker = file->private_data;
105 unsigned long nr_to_scan = 0, read_len;
106 u64 id;
107 struct shrink_control sc = {
108 .gfp_mask = GFP_KERNEL,
109 };
110 struct mem_cgroup *memcg = NULL;
111 int nid;
112 char kbuf[72];
113
114 read_len = min(size, sizeof(kbuf) - 1);
115 if (copy_from_user(kbuf, buf, read_len))
116 return -EFAULT;
117 kbuf[read_len] = '\0';
118
119 if (sscanf(kbuf, "%llu %d %lu", &id, &nid, &nr_to_scan) != 3)
120 return -EINVAL;
121
122 if (nid < 0 || nid >= nr_node_ids)
123 return -EINVAL;
124
125 if (nr_to_scan == 0)
126 return size;
127
128 if (shrinker->flags & SHRINKER_MEMCG_AWARE) {
129 memcg = mem_cgroup_get_from_id(id);
130 if (!memcg)
131 return -ENOENT;
132
133 if (!mem_cgroup_online(memcg)) {
134 mem_cgroup_put(memcg);
135 return -ENOENT;
136 }
137 } else if (id != 0) {
138 return -EINVAL;
139 }
140
141 sc.nid = nid;
142 sc.memcg = memcg;
143 sc.nr_to_scan = nr_to_scan;
144 sc.nr_scanned = nr_to_scan;
145
146 shrinker->scan_objects(shrinker, &sc);
147
148 mem_cgroup_put(memcg);
149
150 return size;
151 }
152
153 static const struct file_operations shrinker_debugfs_scan_fops = {
154 .owner = THIS_MODULE,
155 .open = shrinker_debugfs_scan_open,
156 .write = shrinker_debugfs_scan_write,
157 };
158
shrinker_debugfs_add(struct shrinker * shrinker)159 int shrinker_debugfs_add(struct shrinker *shrinker)
160 {
161 struct dentry *entry;
162 char buf[128];
163 int id;
164
165 lockdep_assert_held(&shrinker_mutex);
166
167 /* debugfs isn't initialized yet, add debugfs entries later. */
168 if (!shrinker_debugfs_root)
169 return 0;
170
171 id = ida_alloc(&shrinker_debugfs_ida, GFP_KERNEL);
172 if (id < 0)
173 return id;
174 shrinker->debugfs_id = id;
175
176 snprintf(buf, sizeof(buf), "%s-%d", shrinker->name, id);
177
178 /* create debugfs entry */
179 entry = debugfs_create_dir(buf, shrinker_debugfs_root);
180 if (IS_ERR(entry)) {
181 ida_free(&shrinker_debugfs_ida, id);
182 return PTR_ERR(entry);
183 }
184 shrinker->debugfs_entry = entry;
185
186 if (shrinker->count_objects)
187 debugfs_create_file("count", 0440, entry, shrinker,
188 &shrinker_debugfs_count_fops);
189 if (shrinker->scan_objects)
190 debugfs_create_file("scan", 0220, entry, shrinker,
191 &shrinker_debugfs_scan_fops);
192 return 0;
193 }
194
shrinker_debugfs_rename(struct shrinker * shrinker,const char * fmt,...)195 int shrinker_debugfs_rename(struct shrinker *shrinker, const char *fmt, ...)
196 {
197 const char *new, *old;
198 va_list ap;
199 int ret = 0;
200
201 va_start(ap, fmt);
202 new = kvasprintf_const(GFP_KERNEL, fmt, ap);
203 va_end(ap);
204
205 if (!new)
206 return -ENOMEM;
207
208 mutex_lock(&shrinker_mutex);
209
210 old = shrinker->name;
211 shrinker->name = new;
212
213 ret = debugfs_change_name(shrinker->debugfs_entry, "%s-%d",
214 shrinker->name, shrinker->debugfs_id);
215
216 if (ret) {
217 shrinker->name = old;
218 kfree_const(new);
219 } else {
220 kfree_const(old);
221 }
222 mutex_unlock(&shrinker_mutex);
223
224 return ret;
225 }
226 EXPORT_SYMBOL(shrinker_debugfs_rename);
227
shrinker_debugfs_detach(struct shrinker * shrinker,int * debugfs_id)228 struct dentry *shrinker_debugfs_detach(struct shrinker *shrinker,
229 int *debugfs_id)
230 {
231 struct dentry *entry = shrinker->debugfs_entry;
232
233 lockdep_assert_held(&shrinker_mutex);
234
235 *debugfs_id = entry ? shrinker->debugfs_id : -1;
236 shrinker->debugfs_entry = NULL;
237
238 return entry;
239 }
240
shrinker_debugfs_remove(struct dentry * debugfs_entry,int debugfs_id)241 void shrinker_debugfs_remove(struct dentry *debugfs_entry, int debugfs_id)
242 {
243 debugfs_remove_recursive(debugfs_entry);
244 ida_free(&shrinker_debugfs_ida, debugfs_id);
245 }
246
shrinker_debugfs_init(void)247 static int __init shrinker_debugfs_init(void)
248 {
249 struct shrinker *shrinker;
250 struct dentry *dentry;
251 int ret = 0;
252
253 dentry = debugfs_create_dir("shrinker", NULL);
254 if (IS_ERR(dentry))
255 return PTR_ERR(dentry);
256 shrinker_debugfs_root = dentry;
257
258 /* Create debugfs entries for shrinkers registered at boot */
259 mutex_lock(&shrinker_mutex);
260 list_for_each_entry(shrinker, &shrinker_list, list)
261 if (!shrinker->debugfs_entry) {
262 ret = shrinker_debugfs_add(shrinker);
263 if (ret)
264 break;
265 }
266 mutex_unlock(&shrinker_mutex);
267
268 return ret;
269 }
270 late_initcall(shrinker_debugfs_init);
271