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