11da177e4SLinus Torvalds 21da177e4SLinus Torvalds #include <linux/mm.h> 31da177e4SLinus Torvalds #include <linux/file.h> 41da177e4SLinus Torvalds #include <linux/mount.h> 55096add8SKees Cook #include <linux/ptrace.h> 61da177e4SLinus Torvalds #include <linux/seq_file.h> 71da177e4SLinus Torvalds #include "internal.h" 81da177e4SLinus Torvalds 91da177e4SLinus Torvalds /* 101da177e4SLinus Torvalds * Logic: we've got two memory sums for each process, "shared", and 111da177e4SLinus Torvalds * "non-shared". Shared memory may get counted more then once, for 121da177e4SLinus Torvalds * each process that owns it. Non-shared memory is counted 131da177e4SLinus Torvalds * accurately. 141da177e4SLinus Torvalds */ 15df5f8314SEric W. Biederman void task_mem(struct seq_file *m, struct mm_struct *mm) 161da177e4SLinus Torvalds { 171da177e4SLinus Torvalds struct vm_list_struct *vml; 181da177e4SLinus Torvalds unsigned long bytes = 0, sbytes = 0, slack = 0; 191da177e4SLinus Torvalds 201da177e4SLinus Torvalds down_read(&mm->mmap_sem); 211da177e4SLinus Torvalds for (vml = mm->context.vmlist; vml; vml = vml->next) { 221da177e4SLinus Torvalds if (!vml->vma) 231da177e4SLinus Torvalds continue; 241da177e4SLinus Torvalds 251da177e4SLinus Torvalds bytes += kobjsize(vml); 261da177e4SLinus Torvalds if (atomic_read(&mm->mm_count) > 1 || 271da177e4SLinus Torvalds atomic_read(&vml->vma->vm_usage) > 1 281da177e4SLinus Torvalds ) { 291da177e4SLinus Torvalds sbytes += kobjsize((void *) vml->vma->vm_start); 301da177e4SLinus Torvalds sbytes += kobjsize(vml->vma); 311da177e4SLinus Torvalds } else { 321da177e4SLinus Torvalds bytes += kobjsize((void *) vml->vma->vm_start); 331da177e4SLinus Torvalds bytes += kobjsize(vml->vma); 341da177e4SLinus Torvalds slack += kobjsize((void *) vml->vma->vm_start) - 351da177e4SLinus Torvalds (vml->vma->vm_end - vml->vma->vm_start); 361da177e4SLinus Torvalds } 371da177e4SLinus Torvalds } 381da177e4SLinus Torvalds 391da177e4SLinus Torvalds if (atomic_read(&mm->mm_count) > 1) 401da177e4SLinus Torvalds sbytes += kobjsize(mm); 411da177e4SLinus Torvalds else 421da177e4SLinus Torvalds bytes += kobjsize(mm); 431da177e4SLinus Torvalds 441da177e4SLinus Torvalds if (current->fs && atomic_read(¤t->fs->count) > 1) 451da177e4SLinus Torvalds sbytes += kobjsize(current->fs); 461da177e4SLinus Torvalds else 471da177e4SLinus Torvalds bytes += kobjsize(current->fs); 481da177e4SLinus Torvalds 491da177e4SLinus Torvalds if (current->files && atomic_read(¤t->files->count) > 1) 501da177e4SLinus Torvalds sbytes += kobjsize(current->files); 511da177e4SLinus Torvalds else 521da177e4SLinus Torvalds bytes += kobjsize(current->files); 531da177e4SLinus Torvalds 541da177e4SLinus Torvalds if (current->sighand && atomic_read(¤t->sighand->count) > 1) 551da177e4SLinus Torvalds sbytes += kobjsize(current->sighand); 561da177e4SLinus Torvalds else 571da177e4SLinus Torvalds bytes += kobjsize(current->sighand); 581da177e4SLinus Torvalds 591da177e4SLinus Torvalds bytes += kobjsize(current); /* includes kernel stack */ 601da177e4SLinus Torvalds 61df5f8314SEric W. Biederman seq_printf(m, 621da177e4SLinus Torvalds "Mem:\t%8lu bytes\n" 631da177e4SLinus Torvalds "Slack:\t%8lu bytes\n" 641da177e4SLinus Torvalds "Shared:\t%8lu bytes\n", 651da177e4SLinus Torvalds bytes, slack, sbytes); 661da177e4SLinus Torvalds 671da177e4SLinus Torvalds up_read(&mm->mmap_sem); 681da177e4SLinus Torvalds } 691da177e4SLinus Torvalds 701da177e4SLinus Torvalds unsigned long task_vsize(struct mm_struct *mm) 711da177e4SLinus Torvalds { 721da177e4SLinus Torvalds struct vm_list_struct *tbp; 731da177e4SLinus Torvalds unsigned long vsize = 0; 741da177e4SLinus Torvalds 751da177e4SLinus Torvalds down_read(&mm->mmap_sem); 761da177e4SLinus Torvalds for (tbp = mm->context.vmlist; tbp; tbp = tbp->next) { 771da177e4SLinus Torvalds if (tbp->vma) 781da177e4SLinus Torvalds vsize += kobjsize((void *) tbp->vma->vm_start); 791da177e4SLinus Torvalds } 801da177e4SLinus Torvalds up_read(&mm->mmap_sem); 811da177e4SLinus Torvalds return vsize; 821da177e4SLinus Torvalds } 831da177e4SLinus Torvalds 841da177e4SLinus Torvalds int task_statm(struct mm_struct *mm, int *shared, int *text, 851da177e4SLinus Torvalds int *data, int *resident) 861da177e4SLinus Torvalds { 871da177e4SLinus Torvalds struct vm_list_struct *tbp; 881da177e4SLinus Torvalds int size = kobjsize(mm); 891da177e4SLinus Torvalds 901da177e4SLinus Torvalds down_read(&mm->mmap_sem); 911da177e4SLinus Torvalds for (tbp = mm->context.vmlist; tbp; tbp = tbp->next) { 921da177e4SLinus Torvalds size += kobjsize(tbp); 931da177e4SLinus Torvalds if (tbp->vma) { 941da177e4SLinus Torvalds size += kobjsize(tbp->vma); 951da177e4SLinus Torvalds size += kobjsize((void *) tbp->vma->vm_start); 961da177e4SLinus Torvalds } 971da177e4SLinus Torvalds } 981da177e4SLinus Torvalds 991da177e4SLinus Torvalds size += (*text = mm->end_code - mm->start_code); 1001da177e4SLinus Torvalds size += (*data = mm->start_stack - mm->start_data); 1011da177e4SLinus Torvalds up_read(&mm->mmap_sem); 1021da177e4SLinus Torvalds *resident = size; 1031da177e4SLinus Torvalds return size; 1041da177e4SLinus Torvalds } 1051da177e4SLinus Torvalds 1061da177e4SLinus Torvalds int proc_exe_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt) 1071da177e4SLinus Torvalds { 1081da177e4SLinus Torvalds struct vm_list_struct *vml; 1091da177e4SLinus Torvalds struct vm_area_struct *vma; 11031304c90SGreg Ungerer struct task_struct *task = get_proc_task(inode); 1111da177e4SLinus Torvalds struct mm_struct *mm = get_task_mm(task); 1121da177e4SLinus Torvalds int result = -ENOENT; 1131da177e4SLinus Torvalds 1141da177e4SLinus Torvalds if (!mm) 1151da177e4SLinus Torvalds goto out; 1161da177e4SLinus Torvalds down_read(&mm->mmap_sem); 1171da177e4SLinus Torvalds 1181da177e4SLinus Torvalds vml = mm->context.vmlist; 1191da177e4SLinus Torvalds vma = NULL; 1201da177e4SLinus Torvalds while (vml) { 1211da177e4SLinus Torvalds if ((vml->vma->vm_flags & VM_EXECUTABLE) && vml->vma->vm_file) { 1221da177e4SLinus Torvalds vma = vml->vma; 1231da177e4SLinus Torvalds break; 1241da177e4SLinus Torvalds } 1251da177e4SLinus Torvalds vml = vml->next; 1261da177e4SLinus Torvalds } 1271da177e4SLinus Torvalds 1281da177e4SLinus Torvalds if (vma) { 1292fddfeefSJosef "Jeff" Sipek *mnt = mntget(vma->vm_file->f_path.mnt); 1302fddfeefSJosef "Jeff" Sipek *dentry = dget(vma->vm_file->f_path.dentry); 1311da177e4SLinus Torvalds result = 0; 1321da177e4SLinus Torvalds } 1331da177e4SLinus Torvalds 1341da177e4SLinus Torvalds up_read(&mm->mmap_sem); 1351da177e4SLinus Torvalds mmput(mm); 1361da177e4SLinus Torvalds out: 1371da177e4SLinus Torvalds return result; 1381da177e4SLinus Torvalds } 1391da177e4SLinus Torvalds 1401da177e4SLinus Torvalds /* 141dbf8685cSDavid Howells * display mapping lines for a particular process's /proc/pid/maps 1421da177e4SLinus Torvalds */ 143dbf8685cSDavid Howells static int show_map(struct seq_file *m, void *_vml) 1441da177e4SLinus Torvalds { 145dbf8685cSDavid Howells struct vm_list_struct *vml = _vml; 1465096add8SKees Cook struct proc_maps_private *priv = m->private; 1475096add8SKees Cook struct task_struct *task = priv->task; 1485096add8SKees Cook 1495096add8SKees Cook if (maps_protect && !ptrace_may_attach(task)) 1505096add8SKees Cook return -EACCES; 1515096add8SKees Cook 152dbf8685cSDavid Howells return nommu_vma_show(m, vml->vma); 1531da177e4SLinus Torvalds } 154dbf8685cSDavid Howells 1551da177e4SLinus Torvalds static void *m_start(struct seq_file *m, loff_t *pos) 1561da177e4SLinus Torvalds { 157dbf8685cSDavid Howells struct proc_maps_private *priv = m->private; 158dbf8685cSDavid Howells struct vm_list_struct *vml; 159dbf8685cSDavid Howells struct mm_struct *mm; 160dbf8685cSDavid Howells loff_t n = *pos; 161dbf8685cSDavid Howells 162dbf8685cSDavid Howells /* pin the task and mm whilst we play with them */ 163dbf8685cSDavid Howells priv->task = get_pid_task(priv->pid, PIDTYPE_PID); 164dbf8685cSDavid Howells if (!priv->task) 165dbf8685cSDavid Howells return NULL; 166dbf8685cSDavid Howells 167831830b5SAl Viro mm = mm_for_maps(priv->task); 168dbf8685cSDavid Howells if (!mm) { 169dbf8685cSDavid Howells put_task_struct(priv->task); 170dbf8685cSDavid Howells priv->task = NULL; 1711da177e4SLinus Torvalds return NULL; 1721da177e4SLinus Torvalds } 173dbf8685cSDavid Howells 174dbf8685cSDavid Howells /* start from the Nth VMA */ 175dbf8685cSDavid Howells for (vml = mm->context.vmlist; vml; vml = vml->next) 176dbf8685cSDavid Howells if (n-- == 0) 177dbf8685cSDavid Howells return vml; 1781da177e4SLinus Torvalds return NULL; 1791da177e4SLinus Torvalds } 180dbf8685cSDavid Howells 181dbf8685cSDavid Howells static void m_stop(struct seq_file *m, void *_vml) 182dbf8685cSDavid Howells { 183dbf8685cSDavid Howells struct proc_maps_private *priv = m->private; 184dbf8685cSDavid Howells 185dbf8685cSDavid Howells if (priv->task) { 186dbf8685cSDavid Howells struct mm_struct *mm = priv->task->mm; 187dbf8685cSDavid Howells up_read(&mm->mmap_sem); 188dbf8685cSDavid Howells mmput(mm); 189dbf8685cSDavid Howells put_task_struct(priv->task); 190dbf8685cSDavid Howells } 191dbf8685cSDavid Howells } 192dbf8685cSDavid Howells 193dbf8685cSDavid Howells static void *m_next(struct seq_file *m, void *_vml, loff_t *pos) 194dbf8685cSDavid Howells { 195dbf8685cSDavid Howells struct vm_list_struct *vml = _vml; 196dbf8685cSDavid Howells 197dbf8685cSDavid Howells (*pos)++; 198dbf8685cSDavid Howells return vml ? vml->next : NULL; 199dbf8685cSDavid Howells } 200dbf8685cSDavid Howells 20103a44825SJan Engelhardt static const struct seq_operations proc_pid_maps_ops = { 2021da177e4SLinus Torvalds .start = m_start, 2031da177e4SLinus Torvalds .next = m_next, 2041da177e4SLinus Torvalds .stop = m_stop, 2051da177e4SLinus Torvalds .show = show_map 2061da177e4SLinus Torvalds }; 207662795deSEric W. Biederman 208662795deSEric W. Biederman static int maps_open(struct inode *inode, struct file *file) 209662795deSEric W. Biederman { 210dbf8685cSDavid Howells struct proc_maps_private *priv; 211dbf8685cSDavid Howells int ret = -ENOMEM; 212dbf8685cSDavid Howells 213dbf8685cSDavid Howells priv = kzalloc(sizeof(*priv), GFP_KERNEL); 214dbf8685cSDavid Howells if (priv) { 215dbf8685cSDavid Howells priv->pid = proc_pid(inode); 216dbf8685cSDavid Howells ret = seq_open(file, &proc_pid_maps_ops); 217662795deSEric W. Biederman if (!ret) { 218662795deSEric W. Biederman struct seq_file *m = file->private_data; 219dbf8685cSDavid Howells m->private = priv; 220dbf8685cSDavid Howells } else { 221dbf8685cSDavid Howells kfree(priv); 222dbf8685cSDavid Howells } 223662795deSEric W. Biederman } 224662795deSEric W. Biederman return ret; 225662795deSEric W. Biederman } 226662795deSEric W. Biederman 22700977a59SArjan van de Ven const struct file_operations proc_maps_operations = { 228662795deSEric W. Biederman .open = maps_open, 229662795deSEric W. Biederman .read = seq_read, 230662795deSEric W. Biederman .llseek = seq_lseek, 231dbf8685cSDavid Howells .release = seq_release_private, 232662795deSEric W. Biederman }; 233662795deSEric W. Biederman 234