1 // SPDX-License-Identifier: GPL-2.0
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>
11 /* defined in vmscan.c */
12 extern struct mutex shrinker_mutex
;
13 extern struct list_head shrinker_list
;
15 static DEFINE_IDA(shrinker_debugfs_ida
);
16 static struct dentry
*shrinker_debugfs_root
;
18 static unsigned long shrinker_count_objects(struct shrinker
*shrinker
,
19 struct mem_cgroup
*memcg
,
20 unsigned long *count_per_node
)
22 unsigned long nr
, total
= 0;
26 if (nid
== 0 || (shrinker
->flags
& SHRINKER_NUMA_AWARE
)) {
27 struct shrink_control sc
= {
28 .gfp_mask
= GFP_KERNEL
,
33 nr
= shrinker
->count_objects(shrinker
, &sc
);
34 if (nr
== SHRINK_EMPTY
)
40 count_per_node
[nid
] = nr
;
47 static int shrinker_debugfs_count_show(struct seq_file
*m
, void *v
)
49 struct shrinker
*shrinker
= m
->private;
50 unsigned long *count_per_node
;
51 struct mem_cgroup
*memcg
;
56 count_per_node
= kcalloc(nr_node_ids
, sizeof(unsigned long), GFP_KERNEL
);
62 memcg_aware
= shrinker
->flags
& SHRINKER_MEMCG_AWARE
;
64 memcg
= mem_cgroup_iter(NULL
, NULL
, NULL
);
66 if (memcg
&& !mem_cgroup_online(memcg
))
69 total
= shrinker_count_objects(shrinker
,
70 memcg_aware
? memcg
: NULL
,
73 seq_printf(m
, "%lu", mem_cgroup_ino(memcg
));
75 seq_printf(m
, " %lu", count_per_node
[nid
]);
80 mem_cgroup_iter_break(NULL
, memcg
);
84 if (signal_pending(current
)) {
85 mem_cgroup_iter_break(NULL
, memcg
);
89 } while ((memcg
= mem_cgroup_iter(NULL
, memcg
, NULL
)) != NULL
);
93 kfree(count_per_node
);
96 DEFINE_SHOW_ATTRIBUTE(shrinker_debugfs_count
);
98 static int shrinker_debugfs_scan_open(struct inode
*inode
, struct file
*file
)
100 file
->private_data
= inode
->i_private
;
101 return nonseekable_open(inode
, file
);
104 static ssize_t
shrinker_debugfs_scan_write(struct file
*file
,
105 const char __user
*buf
,
106 size_t size
, loff_t
*pos
)
108 struct shrinker
*shrinker
= file
->private_data
;
109 unsigned long nr_to_scan
= 0, ino
, read_len
;
110 struct shrink_control sc
= {
111 .gfp_mask
= GFP_KERNEL
,
113 struct mem_cgroup
*memcg
= NULL
;
117 read_len
= min(size
, sizeof(kbuf
) - 1);
118 if (copy_from_user(kbuf
, buf
, read_len
))
120 kbuf
[read_len
] = '\0';
122 if (sscanf(kbuf
, "%lu %d %lu", &ino
, &nid
, &nr_to_scan
) != 3)
125 if (nid
< 0 || nid
>= nr_node_ids
)
131 if (shrinker
->flags
& SHRINKER_MEMCG_AWARE
) {
132 memcg
= mem_cgroup_get_from_ino(ino
);
133 if (!memcg
|| IS_ERR(memcg
))
136 if (!mem_cgroup_online(memcg
)) {
137 mem_cgroup_put(memcg
);
140 } else if (ino
!= 0) {
146 sc
.nr_to_scan
= nr_to_scan
;
147 sc
.nr_scanned
= nr_to_scan
;
149 shrinker
->scan_objects(shrinker
, &sc
);
151 mem_cgroup_put(memcg
);
156 static const struct file_operations shrinker_debugfs_scan_fops
= {
157 .owner
= THIS_MODULE
,
158 .open
= shrinker_debugfs_scan_open
,
159 .write
= shrinker_debugfs_scan_write
,
162 int shrinker_debugfs_add(struct shrinker
*shrinker
)
164 struct dentry
*entry
;
168 lockdep_assert_held(&shrinker_mutex
);
170 /* debugfs isn't initialized yet, add debugfs entries later. */
171 if (!shrinker_debugfs_root
)
174 id
= ida_alloc(&shrinker_debugfs_ida
, GFP_KERNEL
);
177 shrinker
->debugfs_id
= id
;
179 snprintf(buf
, sizeof(buf
), "%s-%d", shrinker
->name
, id
);
181 /* create debugfs entry */
182 entry
= debugfs_create_dir(buf
, shrinker_debugfs_root
);
184 ida_free(&shrinker_debugfs_ida
, id
);
185 return PTR_ERR(entry
);
187 shrinker
->debugfs_entry
= entry
;
189 debugfs_create_file("count", 0440, entry
, shrinker
,
190 &shrinker_debugfs_count_fops
);
191 debugfs_create_file("scan", 0220, entry
, shrinker
,
192 &shrinker_debugfs_scan_fops
);
196 int shrinker_debugfs_rename(struct shrinker
*shrinker
, const char *fmt
, ...)
198 struct dentry
*entry
;
200 const char *new, *old
;
205 new = kvasprintf_const(GFP_KERNEL
, fmt
, ap
);
211 mutex_lock(&shrinker_mutex
);
213 old
= shrinker
->name
;
214 shrinker
->name
= new;
216 if (shrinker
->debugfs_entry
) {
217 snprintf(buf
, sizeof(buf
), "%s-%d", shrinker
->name
,
218 shrinker
->debugfs_id
);
220 entry
= debugfs_rename(shrinker_debugfs_root
,
221 shrinker
->debugfs_entry
,
222 shrinker_debugfs_root
, buf
);
224 ret
= PTR_ERR(entry
);
226 shrinker
->debugfs_entry
= entry
;
229 mutex_unlock(&shrinker_mutex
);
235 EXPORT_SYMBOL(shrinker_debugfs_rename
);
237 struct dentry
*shrinker_debugfs_detach(struct shrinker
*shrinker
,
240 struct dentry
*entry
= shrinker
->debugfs_entry
;
242 lockdep_assert_held(&shrinker_mutex
);
244 *debugfs_id
= entry
? shrinker
->debugfs_id
: -1;
245 shrinker
->debugfs_entry
= NULL
;
250 void shrinker_debugfs_remove(struct dentry
*debugfs_entry
, int debugfs_id
)
252 debugfs_remove_recursive(debugfs_entry
);
253 ida_free(&shrinker_debugfs_ida
, debugfs_id
);
256 static int __init
shrinker_debugfs_init(void)
258 struct shrinker
*shrinker
;
259 struct dentry
*dentry
;
262 dentry
= debugfs_create_dir("shrinker", NULL
);
264 return PTR_ERR(dentry
);
265 shrinker_debugfs_root
= dentry
;
267 /* Create debugfs entries for shrinkers registered at boot */
268 mutex_lock(&shrinker_mutex
);
269 list_for_each_entry(shrinker
, &shrinker_list
, list
)
270 if (!shrinker
->debugfs_entry
) {
271 ret
= shrinker_debugfs_add(shrinker
);
275 mutex_unlock(&shrinker_mutex
);
279 late_initcall(shrinker_debugfs_init
);