11da177e4SLinus Torvalds 21da177e4SLinus Torvalds #include <linux/mm.h> 31da177e4SLinus Torvalds #include <linux/file.h> 4eb28062fSBryan Wu #include <linux/fdtable.h> 51da177e4SLinus Torvalds #include <linux/mount.h> 65096add8SKees Cook #include <linux/ptrace.h> 71da177e4SLinus Torvalds #include <linux/seq_file.h> 81da177e4SLinus Torvalds #include "internal.h" 91da177e4SLinus Torvalds 101da177e4SLinus Torvalds /* 111da177e4SLinus Torvalds * Logic: we've got two memory sums for each process, "shared", and 12025dfdafSFrederik Schwarzer * "non-shared". Shared memory may get counted more than once, for 131da177e4SLinus Torvalds * each process that owns it. Non-shared memory is counted 141da177e4SLinus Torvalds * accurately. 151da177e4SLinus Torvalds */ 16df5f8314SEric W. Biederman void task_mem(struct seq_file *m, struct mm_struct *mm) 171da177e4SLinus Torvalds { 188feae131SDavid Howells struct vm_area_struct *vma; 1938f71479SDavid Howells struct vm_region *region; 208feae131SDavid Howells struct rb_node *p; 2138f71479SDavid Howells unsigned long bytes = 0, sbytes = 0, slack = 0, size; 221da177e4SLinus Torvalds 231da177e4SLinus Torvalds down_read(&mm->mmap_sem); 248feae131SDavid Howells for (p = rb_first(&mm->mm_rb); p; p = rb_next(p)) { 258feae131SDavid Howells vma = rb_entry(p, struct vm_area_struct, vm_rb); 261da177e4SLinus Torvalds 278feae131SDavid Howells bytes += kobjsize(vma); 2838f71479SDavid Howells 2938f71479SDavid Howells region = vma->vm_region; 3038f71479SDavid Howells if (region) { 3138f71479SDavid Howells size = kobjsize(region); 3238f71479SDavid Howells size += region->vm_end - region->vm_start; 331da177e4SLinus Torvalds } else { 3438f71479SDavid Howells size = vma->vm_end - vma->vm_start; 3538f71479SDavid Howells } 3638f71479SDavid Howells 3738f71479SDavid Howells if (atomic_read(&mm->mm_count) > 1 || 3838f71479SDavid Howells vma->vm_flags & VM_MAYSHARE) { 3938f71479SDavid Howells sbytes += size; 4038f71479SDavid Howells } else { 4138f71479SDavid Howells bytes += size; 4238f71479SDavid Howells if (region) 4338f71479SDavid Howells slack = region->vm_end - vma->vm_end; 441da177e4SLinus Torvalds } 451da177e4SLinus Torvalds } 461da177e4SLinus Torvalds 471da177e4SLinus Torvalds if (atomic_read(&mm->mm_count) > 1) 481da177e4SLinus Torvalds sbytes += kobjsize(mm); 491da177e4SLinus Torvalds else 501da177e4SLinus Torvalds bytes += kobjsize(mm); 511da177e4SLinus Torvalds 521da177e4SLinus Torvalds if (current->fs && atomic_read(¤t->fs->count) > 1) 531da177e4SLinus Torvalds sbytes += kobjsize(current->fs); 541da177e4SLinus Torvalds else 551da177e4SLinus Torvalds bytes += kobjsize(current->fs); 561da177e4SLinus Torvalds 571da177e4SLinus Torvalds if (current->files && atomic_read(¤t->files->count) > 1) 581da177e4SLinus Torvalds sbytes += kobjsize(current->files); 591da177e4SLinus Torvalds else 601da177e4SLinus Torvalds bytes += kobjsize(current->files); 611da177e4SLinus Torvalds 621da177e4SLinus Torvalds if (current->sighand && atomic_read(¤t->sighand->count) > 1) 631da177e4SLinus Torvalds sbytes += kobjsize(current->sighand); 641da177e4SLinus Torvalds else 651da177e4SLinus Torvalds bytes += kobjsize(current->sighand); 661da177e4SLinus Torvalds 671da177e4SLinus Torvalds bytes += kobjsize(current); /* includes kernel stack */ 681da177e4SLinus Torvalds 69df5f8314SEric W. Biederman seq_printf(m, 701da177e4SLinus Torvalds "Mem:\t%8lu bytes\n" 711da177e4SLinus Torvalds "Slack:\t%8lu bytes\n" 721da177e4SLinus Torvalds "Shared:\t%8lu bytes\n", 731da177e4SLinus Torvalds bytes, slack, sbytes); 741da177e4SLinus Torvalds 751da177e4SLinus Torvalds up_read(&mm->mmap_sem); 761da177e4SLinus Torvalds } 771da177e4SLinus Torvalds 781da177e4SLinus Torvalds unsigned long task_vsize(struct mm_struct *mm) 791da177e4SLinus Torvalds { 808feae131SDavid Howells struct vm_area_struct *vma; 818feae131SDavid Howells struct rb_node *p; 821da177e4SLinus Torvalds unsigned long vsize = 0; 831da177e4SLinus Torvalds 841da177e4SLinus Torvalds down_read(&mm->mmap_sem); 858feae131SDavid Howells for (p = rb_first(&mm->mm_rb); p; p = rb_next(p)) { 868feae131SDavid Howells vma = rb_entry(p, struct vm_area_struct, vm_rb); 8738f71479SDavid Howells vsize += vma->vm_end - vma->vm_start; 881da177e4SLinus Torvalds } 891da177e4SLinus Torvalds up_read(&mm->mmap_sem); 901da177e4SLinus Torvalds return vsize; 911da177e4SLinus Torvalds } 921da177e4SLinus Torvalds 931da177e4SLinus Torvalds int task_statm(struct mm_struct *mm, int *shared, int *text, 941da177e4SLinus Torvalds int *data, int *resident) 951da177e4SLinus Torvalds { 968feae131SDavid Howells struct vm_area_struct *vma; 9738f71479SDavid Howells struct vm_region *region; 988feae131SDavid Howells struct rb_node *p; 991da177e4SLinus Torvalds int size = kobjsize(mm); 1001da177e4SLinus Torvalds 1011da177e4SLinus Torvalds down_read(&mm->mmap_sem); 1028feae131SDavid Howells for (p = rb_first(&mm->mm_rb); p; p = rb_next(p)) { 1038feae131SDavid Howells vma = rb_entry(p, struct vm_area_struct, vm_rb); 1048feae131SDavid Howells size += kobjsize(vma); 10538f71479SDavid Howells region = vma->vm_region; 10638f71479SDavid Howells if (region) { 10738f71479SDavid Howells size += kobjsize(region); 10838f71479SDavid Howells size += region->vm_end - region->vm_start; 10938f71479SDavid Howells } 1101da177e4SLinus Torvalds } 1111da177e4SLinus Torvalds 1121da177e4SLinus Torvalds size += (*text = mm->end_code - mm->start_code); 1131da177e4SLinus Torvalds size += (*data = mm->start_stack - mm->start_data); 1141da177e4SLinus Torvalds up_read(&mm->mmap_sem); 1151da177e4SLinus Torvalds *resident = size; 1161da177e4SLinus Torvalds return size; 1171da177e4SLinus Torvalds } 1181da177e4SLinus Torvalds 1191da177e4SLinus Torvalds /* 1208feae131SDavid Howells * display a single VMA to a sequenced file 1218feae131SDavid Howells */ 1228feae131SDavid Howells static int nommu_vma_show(struct seq_file *m, struct vm_area_struct *vma) 1238feae131SDavid Howells { 1248feae131SDavid Howells unsigned long ino = 0; 1258feae131SDavid Howells struct file *file; 1268feae131SDavid Howells dev_t dev = 0; 1278feae131SDavid Howells int flags, len; 1288feae131SDavid Howells 1298feae131SDavid Howells flags = vma->vm_flags; 1308feae131SDavid Howells file = vma->vm_file; 1318feae131SDavid Howells 1328feae131SDavid Howells if (file) { 1338feae131SDavid Howells struct inode *inode = vma->vm_file->f_path.dentry->d_inode; 1348feae131SDavid Howells dev = inode->i_sb->s_dev; 1358feae131SDavid Howells ino = inode->i_ino; 1368feae131SDavid Howells } 1378feae131SDavid Howells 1388feae131SDavid Howells seq_printf(m, 13933e5d769SDavid Howells "%08lx-%08lx %c%c%c%c %08llx %02x:%02x %lu %n", 1408feae131SDavid Howells vma->vm_start, 1418feae131SDavid Howells vma->vm_end, 1428feae131SDavid Howells flags & VM_READ ? 'r' : '-', 1438feae131SDavid Howells flags & VM_WRITE ? 'w' : '-', 1448feae131SDavid Howells flags & VM_EXEC ? 'x' : '-', 1458feae131SDavid Howells flags & VM_MAYSHARE ? flags & VM_SHARED ? 'S' : 's' : 'p', 14633e5d769SDavid Howells (unsigned long long) vma->vm_pgoff << PAGE_SHIFT, 1478feae131SDavid Howells MAJOR(dev), MINOR(dev), ino, &len); 1488feae131SDavid Howells 1498feae131SDavid Howells if (file) { 1508feae131SDavid Howells len = 25 + sizeof(void *) * 6 - len; 1518feae131SDavid Howells if (len < 1) 1528feae131SDavid Howells len = 1; 1538feae131SDavid Howells seq_printf(m, "%*c", len, ' '); 1548feae131SDavid Howells seq_path(m, &file->f_path, ""); 1558feae131SDavid Howells } 1568feae131SDavid Howells 1578feae131SDavid Howells seq_putc(m, '\n'); 1588feae131SDavid Howells return 0; 1598feae131SDavid Howells } 1608feae131SDavid Howells 1618feae131SDavid Howells /* 162dbf8685cSDavid Howells * display mapping lines for a particular process's /proc/pid/maps 1631da177e4SLinus Torvalds */ 1648feae131SDavid Howells static int show_map(struct seq_file *m, void *_p) 1651da177e4SLinus Torvalds { 1668feae131SDavid Howells struct rb_node *p = _p; 1675096add8SKees Cook 1688feae131SDavid Howells return nommu_vma_show(m, rb_entry(p, struct vm_area_struct, vm_rb)); 1691da177e4SLinus Torvalds } 170dbf8685cSDavid Howells 1711da177e4SLinus Torvalds static void *m_start(struct seq_file *m, loff_t *pos) 1721da177e4SLinus Torvalds { 173dbf8685cSDavid Howells struct proc_maps_private *priv = m->private; 174dbf8685cSDavid Howells struct mm_struct *mm; 1758feae131SDavid Howells struct rb_node *p; 176dbf8685cSDavid Howells loff_t n = *pos; 177dbf8685cSDavid Howells 178dbf8685cSDavid Howells /* pin the task and mm whilst we play with them */ 179dbf8685cSDavid Howells priv->task = get_pid_task(priv->pid, PIDTYPE_PID); 180dbf8685cSDavid Howells if (!priv->task) 181dbf8685cSDavid Howells return NULL; 182dbf8685cSDavid Howells 183831830b5SAl Viro mm = mm_for_maps(priv->task); 184dbf8685cSDavid Howells if (!mm) { 185dbf8685cSDavid Howells put_task_struct(priv->task); 186dbf8685cSDavid Howells priv->task = NULL; 1871da177e4SLinus Torvalds return NULL; 1881da177e4SLinus Torvalds } 189dbf8685cSDavid Howells 190dbf8685cSDavid Howells /* start from the Nth VMA */ 1918feae131SDavid Howells for (p = rb_first(&mm->mm_rb); p; p = rb_next(p)) 192dbf8685cSDavid Howells if (n-- == 0) 1938feae131SDavid Howells return p; 1941da177e4SLinus Torvalds return NULL; 1951da177e4SLinus Torvalds } 196dbf8685cSDavid Howells 197dbf8685cSDavid Howells static void m_stop(struct seq_file *m, void *_vml) 198dbf8685cSDavid Howells { 199dbf8685cSDavid Howells struct proc_maps_private *priv = m->private; 200dbf8685cSDavid Howells 201dbf8685cSDavid Howells if (priv->task) { 202dbf8685cSDavid Howells struct mm_struct *mm = priv->task->mm; 203dbf8685cSDavid Howells up_read(&mm->mmap_sem); 204dbf8685cSDavid Howells mmput(mm); 205dbf8685cSDavid Howells put_task_struct(priv->task); 206dbf8685cSDavid Howells } 207dbf8685cSDavid Howells } 208dbf8685cSDavid Howells 2098feae131SDavid Howells static void *m_next(struct seq_file *m, void *_p, loff_t *pos) 210dbf8685cSDavid Howells { 2118feae131SDavid Howells struct rb_node *p = _p; 212dbf8685cSDavid Howells 213dbf8685cSDavid Howells (*pos)++; 2148feae131SDavid Howells return p ? rb_next(p) : NULL; 215dbf8685cSDavid Howells } 216dbf8685cSDavid Howells 21703a44825SJan Engelhardt static const struct seq_operations proc_pid_maps_ops = { 2181da177e4SLinus Torvalds .start = m_start, 2191da177e4SLinus Torvalds .next = m_next, 2201da177e4SLinus Torvalds .stop = m_stop, 2211da177e4SLinus Torvalds .show = show_map 2221da177e4SLinus Torvalds }; 223662795deSEric W. Biederman 224662795deSEric W. Biederman static int maps_open(struct inode *inode, struct file *file) 225662795deSEric W. Biederman { 226dbf8685cSDavid Howells struct proc_maps_private *priv; 227dbf8685cSDavid Howells int ret = -ENOMEM; 228dbf8685cSDavid Howells 229dbf8685cSDavid Howells priv = kzalloc(sizeof(*priv), GFP_KERNEL); 230dbf8685cSDavid Howells if (priv) { 231dbf8685cSDavid Howells priv->pid = proc_pid(inode); 232dbf8685cSDavid Howells ret = seq_open(file, &proc_pid_maps_ops); 233662795deSEric W. Biederman if (!ret) { 234662795deSEric W. Biederman struct seq_file *m = file->private_data; 235dbf8685cSDavid Howells m->private = priv; 236dbf8685cSDavid Howells } else { 237dbf8685cSDavid Howells kfree(priv); 238dbf8685cSDavid Howells } 239662795deSEric W. Biederman } 240662795deSEric W. Biederman return ret; 241662795deSEric W. Biederman } 242662795deSEric W. Biederman 24300977a59SArjan van de Ven const struct file_operations proc_maps_operations = { 244662795deSEric W. Biederman .open = maps_open, 245662795deSEric W. Biederman .read = seq_read, 246662795deSEric W. Biederman .llseek = seq_lseek, 247dbf8685cSDavid Howells .release = seq_release_private, 248662795deSEric W. Biederman }; 249662795deSEric W. Biederman 250