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