297 lines · c
1// SPDX-License-Identifier: GPL-2.02 3#include <linux/mm.h>4#include <linux/file.h>5#include <linux/fdtable.h>6#include <linux/fs_struct.h>7#include <linux/mount.h>8#include <linux/ptrace.h>9#include <linux/slab.h>10#include <linux/seq_file.h>11#include <linux/sched/mm.h>12 13#include "internal.h"14 15/*16 * Logic: we've got two memory sums for each process, "shared", and17 * "non-shared". Shared memory may get counted more than once, for18 * each process that owns it. Non-shared memory is counted19 * accurately.20 */21void task_mem(struct seq_file *m, struct mm_struct *mm)22{23 VMA_ITERATOR(vmi, mm, 0);24 struct vm_area_struct *vma;25 struct vm_region *region;26 unsigned long bytes = 0, sbytes = 0, slack = 0, size;27 28 mmap_read_lock(mm);29 for_each_vma(vmi, vma) {30 bytes += kobjsize(vma);31 32 region = vma->vm_region;33 if (region) {34 size = kobjsize(region);35 size += region->vm_end - region->vm_start;36 } else {37 size = vma->vm_end - vma->vm_start;38 }39 40 if (atomic_read(&mm->mm_count) > 1 ||41 is_nommu_shared_mapping(vma->vm_flags)) {42 sbytes += size;43 } else {44 bytes += size;45 if (region)46 slack = region->vm_end - vma->vm_end;47 }48 }49 50 if (atomic_read(&mm->mm_count) > 1)51 sbytes += kobjsize(mm);52 else53 bytes += kobjsize(mm);54 55 if (current->fs && current->fs->users > 1)56 sbytes += kobjsize(current->fs);57 else58 bytes += kobjsize(current->fs);59 60 if (current->files && atomic_read(¤t->files->count) > 1)61 sbytes += kobjsize(current->files);62 else63 bytes += kobjsize(current->files);64 65 if (current->sighand && refcount_read(¤t->sighand->count) > 1)66 sbytes += kobjsize(current->sighand);67 else68 bytes += kobjsize(current->sighand);69 70 bytes += kobjsize(current); /* includes kernel stack */71 72 mmap_read_unlock(mm);73 74 seq_printf(m,75 "Mem:\t%8lu bytes\n"76 "Slack:\t%8lu bytes\n"77 "Shared:\t%8lu bytes\n",78 bytes, slack, sbytes);79}80 81unsigned long task_vsize(struct mm_struct *mm)82{83 VMA_ITERATOR(vmi, mm, 0);84 struct vm_area_struct *vma;85 unsigned long vsize = 0;86 87 mmap_read_lock(mm);88 for_each_vma(vmi, vma)89 vsize += vma->vm_end - vma->vm_start;90 mmap_read_unlock(mm);91 return vsize;92}93 94unsigned long task_statm(struct mm_struct *mm,95 unsigned long *shared, unsigned long *text,96 unsigned long *data, unsigned long *resident)97{98 VMA_ITERATOR(vmi, mm, 0);99 struct vm_area_struct *vma;100 struct vm_region *region;101 unsigned long size = kobjsize(mm);102 103 mmap_read_lock(mm);104 for_each_vma(vmi, vma) {105 size += kobjsize(vma);106 region = vma->vm_region;107 if (region) {108 size += kobjsize(region);109 size += region->vm_end - region->vm_start;110 }111 }112 113 *text = (PAGE_ALIGN(mm->end_code) - (mm->start_code & PAGE_MASK))114 >> PAGE_SHIFT;115 *data = (PAGE_ALIGN(mm->start_stack) - (mm->start_data & PAGE_MASK))116 >> PAGE_SHIFT;117 mmap_read_unlock(mm);118 size >>= PAGE_SHIFT;119 size += *text + *data;120 *resident = size;121 return size;122}123 124/*125 * display a single VMA to a sequenced file126 */127static int nommu_vma_show(struct seq_file *m, struct vm_area_struct *vma)128{129 struct mm_struct *mm = vma->vm_mm;130 unsigned long ino = 0;131 struct file *file;132 dev_t dev = 0;133 int flags;134 unsigned long long pgoff = 0;135 136 flags = vma->vm_flags;137 file = vma->vm_file;138 139 if (file) {140 struct inode *inode = file_inode(vma->vm_file);141 dev = inode->i_sb->s_dev;142 ino = inode->i_ino;143 pgoff = (loff_t)vma->vm_pgoff << PAGE_SHIFT;144 }145 146 seq_setwidth(m, 25 + sizeof(void *) * 6 - 1);147 seq_printf(m,148 "%08lx-%08lx %c%c%c%c %08llx %02x:%02x %lu ",149 vma->vm_start,150 vma->vm_end,151 flags & VM_READ ? 'r' : '-',152 flags & VM_WRITE ? 'w' : '-',153 flags & VM_EXEC ? 'x' : '-',154 flags & VM_MAYSHARE ? flags & VM_SHARED ? 'S' : 's' : 'p',155 pgoff,156 MAJOR(dev), MINOR(dev), ino);157 158 if (file) {159 seq_pad(m, ' ');160 seq_path(m, file_user_path(file), "");161 } else if (mm && vma_is_initial_stack(vma)) {162 seq_pad(m, ' ');163 seq_puts(m, "[stack]");164 }165 166 seq_putc(m, '\n');167 return 0;168}169 170/*171 * display mapping lines for a particular process's /proc/pid/maps172 */173static int show_map(struct seq_file *m, void *_p)174{175 return nommu_vma_show(m, _p);176}177 178static struct vm_area_struct *proc_get_vma(struct proc_maps_private *priv,179 loff_t *ppos)180{181 struct vm_area_struct *vma = vma_next(&priv->iter);182 183 if (vma) {184 *ppos = vma->vm_start;185 } else {186 *ppos = -1UL;187 }188 189 return vma;190}191 192static void *m_start(struct seq_file *m, loff_t *ppos)193{194 struct proc_maps_private *priv = m->private;195 unsigned long last_addr = *ppos;196 struct mm_struct *mm;197 198 /* See proc_get_vma(). Zero at the start or after lseek. */199 if (last_addr == -1UL)200 return NULL;201 202 /* pin the task and mm whilst we play with them */203 priv->task = get_proc_task(priv->inode);204 if (!priv->task)205 return ERR_PTR(-ESRCH);206 207 mm = priv->mm;208 if (!mm || !mmget_not_zero(mm)) {209 put_task_struct(priv->task);210 priv->task = NULL;211 return NULL;212 }213 214 if (mmap_read_lock_killable(mm)) {215 mmput(mm);216 put_task_struct(priv->task);217 priv->task = NULL;218 return ERR_PTR(-EINTR);219 }220 221 vma_iter_init(&priv->iter, mm, last_addr);222 223 return proc_get_vma(priv, ppos);224}225 226static void m_stop(struct seq_file *m, void *v)227{228 struct proc_maps_private *priv = m->private;229 struct mm_struct *mm = priv->mm;230 231 if (!priv->task)232 return;233 234 mmap_read_unlock(mm);235 mmput(mm);236 put_task_struct(priv->task);237 priv->task = NULL;238}239 240static void *m_next(struct seq_file *m, void *_p, loff_t *ppos)241{242 return proc_get_vma(m->private, ppos);243}244 245static const struct seq_operations proc_pid_maps_ops = {246 .start = m_start,247 .next = m_next,248 .stop = m_stop,249 .show = show_map250};251 252static int maps_open(struct inode *inode, struct file *file,253 const struct seq_operations *ops)254{255 struct proc_maps_private *priv;256 257 priv = __seq_open_private(file, ops, sizeof(*priv));258 if (!priv)259 return -ENOMEM;260 261 priv->inode = inode;262 priv->mm = proc_mem_open(inode, PTRACE_MODE_READ);263 if (IS_ERR(priv->mm)) {264 int err = PTR_ERR(priv->mm);265 266 seq_release_private(inode, file);267 return err;268 }269 270 return 0;271}272 273 274static int map_release(struct inode *inode, struct file *file)275{276 struct seq_file *seq = file->private_data;277 struct proc_maps_private *priv = seq->private;278 279 if (priv->mm)280 mmdrop(priv->mm);281 282 return seq_release_private(inode, file);283}284 285static int pid_maps_open(struct inode *inode, struct file *file)286{287 return maps_open(inode, file, &proc_pid_maps_ops);288}289 290const struct file_operations proc_pid_maps_operations = {291 .open = pid_maps_open,292 .read = seq_read,293 .llseek = seq_lseek,294 .release = map_release,295};296 297