11da177e4SLinus Torvalds 21da177e4SLinus Torvalds #include <linux/mm.h> 31da177e4SLinus Torvalds #include <linux/file.h> 41da177e4SLinus Torvalds #include <linux/mount.h> 51da177e4SLinus Torvalds #include <linux/seq_file.h> 61da177e4SLinus Torvalds #include "internal.h" 71da177e4SLinus Torvalds 81da177e4SLinus Torvalds /* 91da177e4SLinus Torvalds * Logic: we've got two memory sums for each process, "shared", and 101da177e4SLinus Torvalds * "non-shared". Shared memory may get counted more then once, for 111da177e4SLinus Torvalds * each process that owns it. Non-shared memory is counted 121da177e4SLinus Torvalds * accurately. 131da177e4SLinus Torvalds */ 141da177e4SLinus Torvalds char *task_mem(struct mm_struct *mm, char *buffer) 151da177e4SLinus Torvalds { 161da177e4SLinus Torvalds struct vm_list_struct *vml; 171da177e4SLinus Torvalds unsigned long bytes = 0, sbytes = 0, slack = 0; 181da177e4SLinus Torvalds 191da177e4SLinus Torvalds down_read(&mm->mmap_sem); 201da177e4SLinus Torvalds for (vml = mm->context.vmlist; vml; vml = vml->next) { 211da177e4SLinus Torvalds if (!vml->vma) 221da177e4SLinus Torvalds continue; 231da177e4SLinus Torvalds 241da177e4SLinus Torvalds bytes += kobjsize(vml); 251da177e4SLinus Torvalds if (atomic_read(&mm->mm_count) > 1 || 261da177e4SLinus Torvalds atomic_read(&vml->vma->vm_usage) > 1 271da177e4SLinus Torvalds ) { 281da177e4SLinus Torvalds sbytes += kobjsize((void *) vml->vma->vm_start); 291da177e4SLinus Torvalds sbytes += kobjsize(vml->vma); 301da177e4SLinus Torvalds } else { 311da177e4SLinus Torvalds bytes += kobjsize((void *) vml->vma->vm_start); 321da177e4SLinus Torvalds bytes += kobjsize(vml->vma); 331da177e4SLinus Torvalds slack += kobjsize((void *) vml->vma->vm_start) - 341da177e4SLinus Torvalds (vml->vma->vm_end - vml->vma->vm_start); 351da177e4SLinus Torvalds } 361da177e4SLinus Torvalds } 371da177e4SLinus Torvalds 381da177e4SLinus Torvalds if (atomic_read(&mm->mm_count) > 1) 391da177e4SLinus Torvalds sbytes += kobjsize(mm); 401da177e4SLinus Torvalds else 411da177e4SLinus Torvalds bytes += kobjsize(mm); 421da177e4SLinus Torvalds 431da177e4SLinus Torvalds if (current->fs && atomic_read(¤t->fs->count) > 1) 441da177e4SLinus Torvalds sbytes += kobjsize(current->fs); 451da177e4SLinus Torvalds else 461da177e4SLinus Torvalds bytes += kobjsize(current->fs); 471da177e4SLinus Torvalds 481da177e4SLinus Torvalds if (current->files && atomic_read(¤t->files->count) > 1) 491da177e4SLinus Torvalds sbytes += kobjsize(current->files); 501da177e4SLinus Torvalds else 511da177e4SLinus Torvalds bytes += kobjsize(current->files); 521da177e4SLinus Torvalds 531da177e4SLinus Torvalds if (current->sighand && atomic_read(¤t->sighand->count) > 1) 541da177e4SLinus Torvalds sbytes += kobjsize(current->sighand); 551da177e4SLinus Torvalds else 561da177e4SLinus Torvalds bytes += kobjsize(current->sighand); 571da177e4SLinus Torvalds 581da177e4SLinus Torvalds bytes += kobjsize(current); /* includes kernel stack */ 591da177e4SLinus Torvalds 601da177e4SLinus Torvalds buffer += sprintf(buffer, 611da177e4SLinus Torvalds "Mem:\t%8lu bytes\n" 621da177e4SLinus Torvalds "Slack:\t%8lu bytes\n" 631da177e4SLinus Torvalds "Shared:\t%8lu bytes\n", 641da177e4SLinus Torvalds bytes, slack, sbytes); 651da177e4SLinus Torvalds 661da177e4SLinus Torvalds up_read(&mm->mmap_sem); 671da177e4SLinus Torvalds return buffer; 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; 146dbf8685cSDavid Howells return nommu_vma_show(m, vml->vma); 1471da177e4SLinus Torvalds } 148dbf8685cSDavid Howells 1491da177e4SLinus Torvalds static void *m_start(struct seq_file *m, loff_t *pos) 1501da177e4SLinus Torvalds { 151dbf8685cSDavid Howells struct proc_maps_private *priv = m->private; 152dbf8685cSDavid Howells struct vm_list_struct *vml; 153dbf8685cSDavid Howells struct mm_struct *mm; 154dbf8685cSDavid Howells loff_t n = *pos; 155dbf8685cSDavid Howells 156dbf8685cSDavid Howells /* pin the task and mm whilst we play with them */ 157dbf8685cSDavid Howells priv->task = get_pid_task(priv->pid, PIDTYPE_PID); 158dbf8685cSDavid Howells if (!priv->task) 159dbf8685cSDavid Howells return NULL; 160dbf8685cSDavid Howells 161dbf8685cSDavid Howells mm = get_task_mm(priv->task); 162dbf8685cSDavid Howells if (!mm) { 163dbf8685cSDavid Howells put_task_struct(priv->task); 164dbf8685cSDavid Howells priv->task = NULL; 1651da177e4SLinus Torvalds return NULL; 1661da177e4SLinus Torvalds } 167dbf8685cSDavid Howells 168dbf8685cSDavid Howells down_read(&mm->mmap_sem); 169dbf8685cSDavid Howells 170dbf8685cSDavid Howells /* start from the Nth VMA */ 171dbf8685cSDavid Howells for (vml = mm->context.vmlist; vml; vml = vml->next) 172dbf8685cSDavid Howells if (n-- == 0) 173dbf8685cSDavid Howells return vml; 1741da177e4SLinus Torvalds return NULL; 1751da177e4SLinus Torvalds } 176dbf8685cSDavid Howells 177dbf8685cSDavid Howells static void m_stop(struct seq_file *m, void *_vml) 178dbf8685cSDavid Howells { 179dbf8685cSDavid Howells struct proc_maps_private *priv = m->private; 180dbf8685cSDavid Howells 181dbf8685cSDavid Howells if (priv->task) { 182dbf8685cSDavid Howells struct mm_struct *mm = priv->task->mm; 183dbf8685cSDavid Howells up_read(&mm->mmap_sem); 184dbf8685cSDavid Howells mmput(mm); 185dbf8685cSDavid Howells put_task_struct(priv->task); 186dbf8685cSDavid Howells } 187dbf8685cSDavid Howells } 188dbf8685cSDavid Howells 189dbf8685cSDavid Howells static void *m_next(struct seq_file *m, void *_vml, loff_t *pos) 190dbf8685cSDavid Howells { 191dbf8685cSDavid Howells struct vm_list_struct *vml = _vml; 192dbf8685cSDavid Howells 193dbf8685cSDavid Howells (*pos)++; 194dbf8685cSDavid Howells return vml ? vml->next : NULL; 195dbf8685cSDavid Howells } 196dbf8685cSDavid Howells 197dbf8685cSDavid Howells static struct seq_operations proc_pid_maps_ops = { 1981da177e4SLinus Torvalds .start = m_start, 1991da177e4SLinus Torvalds .next = m_next, 2001da177e4SLinus Torvalds .stop = m_stop, 2011da177e4SLinus Torvalds .show = show_map 2021da177e4SLinus Torvalds }; 203662795deSEric W. Biederman 204662795deSEric W. Biederman static int maps_open(struct inode *inode, struct file *file) 205662795deSEric W. Biederman { 206dbf8685cSDavid Howells struct proc_maps_private *priv; 207dbf8685cSDavid Howells int ret = -ENOMEM; 208dbf8685cSDavid Howells 209dbf8685cSDavid Howells priv = kzalloc(sizeof(*priv), GFP_KERNEL); 210dbf8685cSDavid Howells if (priv) { 211dbf8685cSDavid Howells priv->pid = proc_pid(inode); 212dbf8685cSDavid Howells ret = seq_open(file, &proc_pid_maps_ops); 213662795deSEric W. Biederman if (!ret) { 214662795deSEric W. Biederman struct seq_file *m = file->private_data; 215dbf8685cSDavid Howells m->private = priv; 216dbf8685cSDavid Howells } else { 217dbf8685cSDavid Howells kfree(priv); 218dbf8685cSDavid Howells } 219662795deSEric W. Biederman } 220662795deSEric W. Biederman return ret; 221662795deSEric W. Biederman } 222662795deSEric W. Biederman 22300977a59SArjan van de Ven const struct file_operations proc_maps_operations = { 224662795deSEric W. Biederman .open = maps_open, 225662795deSEric W. Biederman .read = seq_read, 226662795deSEric W. Biederman .llseek = seq_lseek, 227dbf8685cSDavid Howells .release = seq_release_private, 228662795deSEric W. Biederman }; 229662795deSEric W. Biederman 230