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 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 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 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 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 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 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 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 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 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