11da177e4SLinus Torvalds 21da177e4SLinus Torvalds #include <linux/mm.h> 31da177e4SLinus Torvalds #include <linux/file.h> 4eb28062fSBryan Wu #include <linux/fdtable.h> 55ad4e53bSAl Viro #include <linux/fs_struct.h> 61da177e4SLinus Torvalds #include <linux/mount.h> 75096add8SKees Cook #include <linux/ptrace.h> 81da177e4SLinus Torvalds #include <linux/seq_file.h> 91da177e4SLinus Torvalds #include "internal.h" 101da177e4SLinus Torvalds 111da177e4SLinus Torvalds /* 121da177e4SLinus Torvalds * Logic: we've got two memory sums for each process, "shared", and 13025dfdafSFrederik Schwarzer * "non-shared". Shared memory may get counted more than once, for 141da177e4SLinus Torvalds * each process that owns it. Non-shared memory is counted 151da177e4SLinus Torvalds * accurately. 161da177e4SLinus Torvalds */ 17df5f8314SEric W. Biederman void task_mem(struct seq_file *m, struct mm_struct *mm) 181da177e4SLinus Torvalds { 198feae131SDavid Howells struct vm_area_struct *vma; 2038f71479SDavid Howells struct vm_region *region; 218feae131SDavid Howells struct rb_node *p; 2238f71479SDavid Howells unsigned long bytes = 0, sbytes = 0, slack = 0, size; 231da177e4SLinus Torvalds 241da177e4SLinus Torvalds down_read(&mm->mmap_sem); 258feae131SDavid Howells for (p = rb_first(&mm->mm_rb); p; p = rb_next(p)) { 268feae131SDavid Howells vma = rb_entry(p, struct vm_area_struct, vm_rb); 271da177e4SLinus Torvalds 288feae131SDavid Howells bytes += kobjsize(vma); 2938f71479SDavid Howells 3038f71479SDavid Howells region = vma->vm_region; 3138f71479SDavid Howells if (region) { 3238f71479SDavid Howells size = kobjsize(region); 3338f71479SDavid Howells size += region->vm_end - region->vm_start; 341da177e4SLinus Torvalds } else { 3538f71479SDavid Howells size = vma->vm_end - vma->vm_start; 3638f71479SDavid Howells } 3738f71479SDavid Howells 3838f71479SDavid Howells if (atomic_read(&mm->mm_count) > 1 || 3938f71479SDavid Howells vma->vm_flags & VM_MAYSHARE) { 4038f71479SDavid Howells sbytes += size; 4138f71479SDavid Howells } else { 4238f71479SDavid Howells bytes += size; 4338f71479SDavid Howells if (region) 4438f71479SDavid Howells slack = region->vm_end - vma->vm_end; 451da177e4SLinus Torvalds } 461da177e4SLinus Torvalds } 471da177e4SLinus Torvalds 481da177e4SLinus Torvalds if (atomic_read(&mm->mm_count) > 1) 491da177e4SLinus Torvalds sbytes += kobjsize(mm); 501da177e4SLinus Torvalds else 511da177e4SLinus Torvalds bytes += kobjsize(mm); 521da177e4SLinus Torvalds 53498052bbSAl Viro if (current->fs && current->fs->users > 1) 541da177e4SLinus Torvalds sbytes += kobjsize(current->fs); 551da177e4SLinus Torvalds else 561da177e4SLinus Torvalds bytes += kobjsize(current->fs); 571da177e4SLinus Torvalds 581da177e4SLinus Torvalds if (current->files && atomic_read(¤t->files->count) > 1) 591da177e4SLinus Torvalds sbytes += kobjsize(current->files); 601da177e4SLinus Torvalds else 611da177e4SLinus Torvalds bytes += kobjsize(current->files); 621da177e4SLinus Torvalds 631da177e4SLinus Torvalds if (current->sighand && atomic_read(¤t->sighand->count) > 1) 641da177e4SLinus Torvalds sbytes += kobjsize(current->sighand); 651da177e4SLinus Torvalds else 661da177e4SLinus Torvalds bytes += kobjsize(current->sighand); 671da177e4SLinus Torvalds 681da177e4SLinus Torvalds bytes += kobjsize(current); /* includes kernel stack */ 691da177e4SLinus Torvalds 70df5f8314SEric W. Biederman seq_printf(m, 711da177e4SLinus Torvalds "Mem:\t%8lu bytes\n" 721da177e4SLinus Torvalds "Slack:\t%8lu bytes\n" 731da177e4SLinus Torvalds "Shared:\t%8lu bytes\n", 741da177e4SLinus Torvalds bytes, slack, sbytes); 751da177e4SLinus Torvalds 761da177e4SLinus Torvalds up_read(&mm->mmap_sem); 771da177e4SLinus Torvalds } 781da177e4SLinus Torvalds 791da177e4SLinus Torvalds unsigned long task_vsize(struct mm_struct *mm) 801da177e4SLinus Torvalds { 818feae131SDavid Howells struct vm_area_struct *vma; 828feae131SDavid Howells struct rb_node *p; 831da177e4SLinus Torvalds unsigned long vsize = 0; 841da177e4SLinus Torvalds 851da177e4SLinus Torvalds down_read(&mm->mmap_sem); 868feae131SDavid Howells for (p = rb_first(&mm->mm_rb); p; p = rb_next(p)) { 878feae131SDavid Howells vma = rb_entry(p, struct vm_area_struct, vm_rb); 8838f71479SDavid Howells vsize += vma->vm_end - vma->vm_start; 891da177e4SLinus Torvalds } 901da177e4SLinus Torvalds up_read(&mm->mmap_sem); 911da177e4SLinus Torvalds return vsize; 921da177e4SLinus Torvalds } 931da177e4SLinus Torvalds 941da177e4SLinus Torvalds int task_statm(struct mm_struct *mm, int *shared, int *text, 951da177e4SLinus Torvalds int *data, int *resident) 961da177e4SLinus Torvalds { 978feae131SDavid Howells struct vm_area_struct *vma; 9838f71479SDavid Howells struct vm_region *region; 998feae131SDavid Howells struct rb_node *p; 1001da177e4SLinus Torvalds int size = kobjsize(mm); 1011da177e4SLinus Torvalds 1021da177e4SLinus Torvalds down_read(&mm->mmap_sem); 1038feae131SDavid Howells for (p = rb_first(&mm->mm_rb); p; p = rb_next(p)) { 1048feae131SDavid Howells vma = rb_entry(p, struct vm_area_struct, vm_rb); 1058feae131SDavid Howells size += kobjsize(vma); 10638f71479SDavid Howells region = vma->vm_region; 10738f71479SDavid Howells if (region) { 10838f71479SDavid Howells size += kobjsize(region); 10938f71479SDavid Howells size += region->vm_end - region->vm_start; 11038f71479SDavid Howells } 1111da177e4SLinus Torvalds } 1121da177e4SLinus Torvalds 1131da177e4SLinus Torvalds size += (*text = mm->end_code - mm->start_code); 1141da177e4SLinus Torvalds size += (*data = mm->start_stack - mm->start_data); 1151da177e4SLinus Torvalds up_read(&mm->mmap_sem); 1161da177e4SLinus Torvalds *resident = size; 1171da177e4SLinus Torvalds return size; 1181da177e4SLinus Torvalds } 1191da177e4SLinus Torvalds 1201da177e4SLinus Torvalds /* 1218feae131SDavid Howells * display a single VMA to a sequenced file 1228feae131SDavid Howells */ 1238feae131SDavid Howells static int nommu_vma_show(struct seq_file *m, struct vm_area_struct *vma) 1248feae131SDavid Howells { 1258feae131SDavid Howells unsigned long ino = 0; 1268feae131SDavid Howells struct file *file; 1278feae131SDavid Howells dev_t dev = 0; 1288feae131SDavid Howells int flags, len; 1296260a4b0SKAMEZAWA Hiroyuki unsigned long long pgoff = 0; 1308feae131SDavid Howells 1318feae131SDavid Howells flags = vma->vm_flags; 1328feae131SDavid Howells file = vma->vm_file; 1338feae131SDavid Howells 1348feae131SDavid Howells if (file) { 1358feae131SDavid Howells struct inode *inode = vma->vm_file->f_path.dentry->d_inode; 1368feae131SDavid Howells dev = inode->i_sb->s_dev; 1378feae131SDavid Howells ino = inode->i_ino; 1384c967291SNobuhiro Iwamatsu pgoff = (loff_t)vma->vm_pgoff << PAGE_SHIFT; 1398feae131SDavid Howells } 1408feae131SDavid Howells 1418feae131SDavid Howells seq_printf(m, 14233e5d769SDavid Howells "%08lx-%08lx %c%c%c%c %08llx %02x:%02x %lu %n", 1438feae131SDavid Howells vma->vm_start, 1448feae131SDavid Howells vma->vm_end, 1458feae131SDavid Howells flags & VM_READ ? 'r' : '-', 1468feae131SDavid Howells flags & VM_WRITE ? 'w' : '-', 1478feae131SDavid Howells flags & VM_EXEC ? 'x' : '-', 1488feae131SDavid Howells flags & VM_MAYSHARE ? flags & VM_SHARED ? 'S' : 's' : 'p', 1496260a4b0SKAMEZAWA Hiroyuki pgoff, 1508feae131SDavid Howells MAJOR(dev), MINOR(dev), ino, &len); 1518feae131SDavid Howells 1528feae131SDavid Howells if (file) { 1538feae131SDavid Howells len = 25 + sizeof(void *) * 6 - len; 1548feae131SDavid Howells if (len < 1) 1558feae131SDavid Howells len = 1; 1568feae131SDavid Howells seq_printf(m, "%*c", len, ' '); 1578feae131SDavid Howells seq_path(m, &file->f_path, ""); 1588feae131SDavid Howells } 1598feae131SDavid Howells 1608feae131SDavid Howells seq_putc(m, '\n'); 1618feae131SDavid Howells return 0; 1628feae131SDavid Howells } 1638feae131SDavid Howells 1648feae131SDavid Howells /* 165dbf8685cSDavid Howells * display mapping lines for a particular process's /proc/pid/maps 1661da177e4SLinus Torvalds */ 1678feae131SDavid Howells static int show_map(struct seq_file *m, void *_p) 1681da177e4SLinus Torvalds { 1698feae131SDavid Howells struct rb_node *p = _p; 1705096add8SKees Cook 1718feae131SDavid Howells return nommu_vma_show(m, rb_entry(p, struct vm_area_struct, vm_rb)); 1721da177e4SLinus Torvalds } 173dbf8685cSDavid Howells 1741da177e4SLinus Torvalds static void *m_start(struct seq_file *m, loff_t *pos) 1751da177e4SLinus Torvalds { 176dbf8685cSDavid Howells struct proc_maps_private *priv = m->private; 177dbf8685cSDavid Howells struct mm_struct *mm; 1788feae131SDavid Howells struct rb_node *p; 179dbf8685cSDavid Howells loff_t n = *pos; 180dbf8685cSDavid Howells 181dbf8685cSDavid Howells /* pin the task and mm whilst we play with them */ 182dbf8685cSDavid Howells priv->task = get_pid_task(priv->pid, PIDTYPE_PID); 183dbf8685cSDavid Howells if (!priv->task) 184dbf8685cSDavid Howells return NULL; 185dbf8685cSDavid Howells 186831830b5SAl Viro mm = mm_for_maps(priv->task); 187dbf8685cSDavid Howells if (!mm) { 188dbf8685cSDavid Howells put_task_struct(priv->task); 189dbf8685cSDavid Howells priv->task = NULL; 1901da177e4SLinus Torvalds return NULL; 1911da177e4SLinus Torvalds } 192dbf8685cSDavid Howells 193dbf8685cSDavid Howells /* start from the Nth VMA */ 1948feae131SDavid Howells for (p = rb_first(&mm->mm_rb); p; p = rb_next(p)) 195dbf8685cSDavid Howells if (n-- == 0) 1968feae131SDavid Howells return p; 1971da177e4SLinus Torvalds return NULL; 1981da177e4SLinus Torvalds } 199dbf8685cSDavid Howells 200dbf8685cSDavid Howells static void m_stop(struct seq_file *m, void *_vml) 201dbf8685cSDavid Howells { 202dbf8685cSDavid Howells struct proc_maps_private *priv = m->private; 203dbf8685cSDavid Howells 204dbf8685cSDavid Howells if (priv->task) { 205dbf8685cSDavid Howells struct mm_struct *mm = priv->task->mm; 206dbf8685cSDavid Howells up_read(&mm->mmap_sem); 207dbf8685cSDavid Howells mmput(mm); 208dbf8685cSDavid Howells put_task_struct(priv->task); 209dbf8685cSDavid Howells } 210dbf8685cSDavid Howells } 211dbf8685cSDavid Howells 2128feae131SDavid Howells static void *m_next(struct seq_file *m, void *_p, loff_t *pos) 213dbf8685cSDavid Howells { 2148feae131SDavid Howells struct rb_node *p = _p; 215dbf8685cSDavid Howells 216dbf8685cSDavid Howells (*pos)++; 2178feae131SDavid Howells return p ? rb_next(p) : NULL; 218dbf8685cSDavid Howells } 219dbf8685cSDavid Howells 22003a44825SJan Engelhardt static const struct seq_operations proc_pid_maps_ops = { 2211da177e4SLinus Torvalds .start = m_start, 2221da177e4SLinus Torvalds .next = m_next, 2231da177e4SLinus Torvalds .stop = m_stop, 2241da177e4SLinus Torvalds .show = show_map 2251da177e4SLinus Torvalds }; 226662795deSEric W. Biederman 227662795deSEric W. Biederman static int maps_open(struct inode *inode, struct file *file) 228662795deSEric W. Biederman { 229dbf8685cSDavid Howells struct proc_maps_private *priv; 230dbf8685cSDavid Howells int ret = -ENOMEM; 231dbf8685cSDavid Howells 232dbf8685cSDavid Howells priv = kzalloc(sizeof(*priv), GFP_KERNEL); 233dbf8685cSDavid Howells if (priv) { 234dbf8685cSDavid Howells priv->pid = proc_pid(inode); 235dbf8685cSDavid Howells ret = seq_open(file, &proc_pid_maps_ops); 236662795deSEric W. Biederman if (!ret) { 237662795deSEric W. Biederman struct seq_file *m = file->private_data; 238dbf8685cSDavid Howells m->private = priv; 239dbf8685cSDavid Howells } else { 240dbf8685cSDavid Howells kfree(priv); 241dbf8685cSDavid Howells } 242662795deSEric W. Biederman } 243662795deSEric W. Biederman return ret; 244662795deSEric W. Biederman } 245662795deSEric W. Biederman 24600977a59SArjan van de Ven const struct file_operations proc_maps_operations = { 247662795deSEric W. Biederman .open = maps_open, 248662795deSEric W. Biederman .read = seq_read, 249662795deSEric W. Biederman .llseek = seq_lseek, 250dbf8685cSDavid Howells .release = seq_release_private, 251662795deSEric W. Biederman }; 252662795deSEric W. Biederman 253