Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 #include <linux/idr.h>
0003 #include <linux/slab.h>
0004 #include <linux/debugfs.h>
0005 #include <linux/seq_file.h>
0006 #include <linux/shrinker.h>
0007 #include <linux/memcontrol.h>
0008 
0009 /* defined in vmscan.c */
0010 extern struct rw_semaphore shrinker_rwsem;
0011 extern struct list_head shrinker_list;
0012 
0013 static DEFINE_IDA(shrinker_debugfs_ida);
0014 static struct dentry *shrinker_debugfs_root;
0015 
0016 static unsigned long shrinker_count_objects(struct shrinker *shrinker,
0017                         struct mem_cgroup *memcg,
0018                         unsigned long *count_per_node)
0019 {
0020     unsigned long nr, total = 0;
0021     int nid;
0022 
0023     for_each_node(nid) {
0024         if (nid == 0 || (shrinker->flags & SHRINKER_NUMA_AWARE)) {
0025             struct shrink_control sc = {
0026                 .gfp_mask = GFP_KERNEL,
0027                 .nid = nid,
0028                 .memcg = memcg,
0029             };
0030 
0031             nr = shrinker->count_objects(shrinker, &sc);
0032             if (nr == SHRINK_EMPTY)
0033                 nr = 0;
0034         } else {
0035             nr = 0;
0036         }
0037 
0038         count_per_node[nid] = nr;
0039         total += nr;
0040     }
0041 
0042     return total;
0043 }
0044 
0045 static int shrinker_debugfs_count_show(struct seq_file *m, void *v)
0046 {
0047     struct shrinker *shrinker = m->private;
0048     unsigned long *count_per_node;
0049     struct mem_cgroup *memcg;
0050     unsigned long total;
0051     bool memcg_aware;
0052     int ret, nid;
0053 
0054     count_per_node = kcalloc(nr_node_ids, sizeof(unsigned long), GFP_KERNEL);
0055     if (!count_per_node)
0056         return -ENOMEM;
0057 
0058     ret = down_read_killable(&shrinker_rwsem);
0059     if (ret) {
0060         kfree(count_per_node);
0061         return ret;
0062     }
0063     rcu_read_lock();
0064 
0065     memcg_aware = shrinker->flags & SHRINKER_MEMCG_AWARE;
0066 
0067     memcg = mem_cgroup_iter(NULL, NULL, NULL);
0068     do {
0069         if (memcg && !mem_cgroup_online(memcg))
0070             continue;
0071 
0072         total = shrinker_count_objects(shrinker,
0073                            memcg_aware ? memcg : NULL,
0074                            count_per_node);
0075         if (total) {
0076             seq_printf(m, "%lu", mem_cgroup_ino(memcg));
0077             for_each_node(nid)
0078                 seq_printf(m, " %lu", count_per_node[nid]);
0079             seq_putc(m, '\n');
0080         }
0081 
0082         if (!memcg_aware) {
0083             mem_cgroup_iter_break(NULL, memcg);
0084             break;
0085         }
0086 
0087         if (signal_pending(current)) {
0088             mem_cgroup_iter_break(NULL, memcg);
0089             ret = -EINTR;
0090             break;
0091         }
0092     } while ((memcg = mem_cgroup_iter(NULL, memcg, NULL)) != NULL);
0093 
0094     rcu_read_unlock();
0095     up_read(&shrinker_rwsem);
0096 
0097     kfree(count_per_node);
0098     return ret;
0099 }
0100 DEFINE_SHOW_ATTRIBUTE(shrinker_debugfs_count);
0101 
0102 static int shrinker_debugfs_scan_open(struct inode *inode, struct file *file)
0103 {
0104     file->private_data = inode->i_private;
0105     return nonseekable_open(inode, file);
0106 }
0107 
0108 static ssize_t shrinker_debugfs_scan_write(struct file *file,
0109                        const char __user *buf,
0110                        size_t size, loff_t *pos)
0111 {
0112     struct shrinker *shrinker = file->private_data;
0113     unsigned long nr_to_scan = 0, ino, read_len;
0114     struct shrink_control sc = {
0115         .gfp_mask = GFP_KERNEL,
0116     };
0117     struct mem_cgroup *memcg = NULL;
0118     int nid;
0119     char kbuf[72];
0120     ssize_t ret;
0121 
0122     read_len = size < (sizeof(kbuf) - 1) ? size : (sizeof(kbuf) - 1);
0123     if (copy_from_user(kbuf, buf, read_len))
0124         return -EFAULT;
0125     kbuf[read_len] = '\0';
0126 
0127     if (sscanf(kbuf, "%lu %d %lu", &ino, &nid, &nr_to_scan) != 3)
0128         return -EINVAL;
0129 
0130     if (nid < 0 || nid >= nr_node_ids)
0131         return -EINVAL;
0132 
0133     if (nr_to_scan == 0)
0134         return size;
0135 
0136     if (shrinker->flags & SHRINKER_MEMCG_AWARE) {
0137         memcg = mem_cgroup_get_from_ino(ino);
0138         if (!memcg || IS_ERR(memcg))
0139             return -ENOENT;
0140 
0141         if (!mem_cgroup_online(memcg)) {
0142             mem_cgroup_put(memcg);
0143             return -ENOENT;
0144         }
0145     } else if (ino != 0) {
0146         return -EINVAL;
0147     }
0148 
0149     ret = down_read_killable(&shrinker_rwsem);
0150     if (ret) {
0151         mem_cgroup_put(memcg);
0152         return ret;
0153     }
0154 
0155     sc.nid = nid;
0156     sc.memcg = memcg;
0157     sc.nr_to_scan = nr_to_scan;
0158     sc.nr_scanned = nr_to_scan;
0159 
0160     shrinker->scan_objects(shrinker, &sc);
0161 
0162     up_read(&shrinker_rwsem);
0163     mem_cgroup_put(memcg);
0164 
0165     return size;
0166 }
0167 
0168 static const struct file_operations shrinker_debugfs_scan_fops = {
0169     .owner   = THIS_MODULE,
0170     .open    = shrinker_debugfs_scan_open,
0171     .write   = shrinker_debugfs_scan_write,
0172 };
0173 
0174 int shrinker_debugfs_add(struct shrinker *shrinker)
0175 {
0176     struct dentry *entry;
0177     char buf[128];
0178     int id;
0179 
0180     lockdep_assert_held(&shrinker_rwsem);
0181 
0182     /* debugfs isn't initialized yet, add debugfs entries later. */
0183     if (!shrinker_debugfs_root)
0184         return 0;
0185 
0186     id = ida_alloc(&shrinker_debugfs_ida, GFP_KERNEL);
0187     if (id < 0)
0188         return id;
0189     shrinker->debugfs_id = id;
0190 
0191     snprintf(buf, sizeof(buf), "%s-%d", shrinker->name, id);
0192 
0193     /* create debugfs entry */
0194     entry = debugfs_create_dir(buf, shrinker_debugfs_root);
0195     if (IS_ERR(entry)) {
0196         ida_free(&shrinker_debugfs_ida, id);
0197         return PTR_ERR(entry);
0198     }
0199     shrinker->debugfs_entry = entry;
0200 
0201     debugfs_create_file("count", 0220, entry, shrinker,
0202                 &shrinker_debugfs_count_fops);
0203     debugfs_create_file("scan", 0440, entry, shrinker,
0204                 &shrinker_debugfs_scan_fops);
0205     return 0;
0206 }
0207 
0208 int shrinker_debugfs_rename(struct shrinker *shrinker, const char *fmt, ...)
0209 {
0210     struct dentry *entry;
0211     char buf[128];
0212     const char *new, *old;
0213     va_list ap;
0214     int ret = 0;
0215 
0216     va_start(ap, fmt);
0217     new = kvasprintf_const(GFP_KERNEL, fmt, ap);
0218     va_end(ap);
0219 
0220     if (!new)
0221         return -ENOMEM;
0222 
0223     down_write(&shrinker_rwsem);
0224 
0225     old = shrinker->name;
0226     shrinker->name = new;
0227 
0228     if (shrinker->debugfs_entry) {
0229         snprintf(buf, sizeof(buf), "%s-%d", shrinker->name,
0230              shrinker->debugfs_id);
0231 
0232         entry = debugfs_rename(shrinker_debugfs_root,
0233                        shrinker->debugfs_entry,
0234                        shrinker_debugfs_root, buf);
0235         if (IS_ERR(entry))
0236             ret = PTR_ERR(entry);
0237         else
0238             shrinker->debugfs_entry = entry;
0239     }
0240 
0241     up_write(&shrinker_rwsem);
0242 
0243     kfree_const(old);
0244 
0245     return ret;
0246 }
0247 EXPORT_SYMBOL(shrinker_debugfs_rename);
0248 
0249 void shrinker_debugfs_remove(struct shrinker *shrinker)
0250 {
0251     lockdep_assert_held(&shrinker_rwsem);
0252 
0253     kfree_const(shrinker->name);
0254     shrinker->name = NULL;
0255 
0256     if (!shrinker->debugfs_entry)
0257         return;
0258 
0259     debugfs_remove_recursive(shrinker->debugfs_entry);
0260     ida_free(&shrinker_debugfs_ida, shrinker->debugfs_id);
0261 }
0262 
0263 static int __init shrinker_debugfs_init(void)
0264 {
0265     struct shrinker *shrinker;
0266     struct dentry *dentry;
0267     int ret = 0;
0268 
0269     dentry = debugfs_create_dir("shrinker", NULL);
0270     if (IS_ERR(dentry))
0271         return PTR_ERR(dentry);
0272     shrinker_debugfs_root = dentry;
0273 
0274     /* Create debugfs entries for shrinkers registered at boot */
0275     down_write(&shrinker_rwsem);
0276     list_for_each_entry(shrinker, &shrinker_list, list)
0277         if (!shrinker->debugfs_entry) {
0278             ret = shrinker_debugfs_add(shrinker);
0279             if (ret)
0280                 break;
0281         }
0282     up_write(&shrinker_rwsem);
0283 
0284     return ret;
0285 }
0286 late_initcall(shrinker_debugfs_init);