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) { 1291da177e4SLinus Torvalds *mnt = mntget(vma->vm_file->f_vfsmnt); 1301da177e4SLinus Torvalds *dentry = dget(vma->vm_file->f_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 /* 1411da177e4SLinus Torvalds * Albert D. Cahalan suggested to fake entries for the traditional 1421da177e4SLinus Torvalds * sections here. This might be worth investigating. 1431da177e4SLinus Torvalds */ 1441da177e4SLinus Torvalds static int show_map(struct seq_file *m, void *v) 1451da177e4SLinus Torvalds { 1461da177e4SLinus Torvalds return 0; 1471da177e4SLinus Torvalds } 1481da177e4SLinus Torvalds static void *m_start(struct seq_file *m, loff_t *pos) 1491da177e4SLinus Torvalds { 1501da177e4SLinus Torvalds return NULL; 1511da177e4SLinus Torvalds } 1521da177e4SLinus Torvalds static void m_stop(struct seq_file *m, void *v) 1531da177e4SLinus Torvalds { 1541da177e4SLinus Torvalds } 1551da177e4SLinus Torvalds static void *m_next(struct seq_file *m, void *v, loff_t *pos) 1561da177e4SLinus Torvalds { 1571da177e4SLinus Torvalds return NULL; 1581da177e4SLinus Torvalds } 159662795deSEric W. Biederman static struct seq_operations proc_pid_maps_op = { 1601da177e4SLinus Torvalds .start = m_start, 1611da177e4SLinus Torvalds .next = m_next, 1621da177e4SLinus Torvalds .stop = m_stop, 1631da177e4SLinus Torvalds .show = show_map 1641da177e4SLinus Torvalds }; 165662795deSEric W. Biederman 166662795deSEric W. Biederman static int maps_open(struct inode *inode, struct file *file) 167662795deSEric W. Biederman { 168662795deSEric W. Biederman int ret; 169662795deSEric W. Biederman ret = seq_open(file, &proc_pid_maps_op); 170662795deSEric W. Biederman if (!ret) { 171662795deSEric W. Biederman struct seq_file *m = file->private_data; 172662795deSEric W. Biederman m->private = NULL; 173662795deSEric W. Biederman } 174662795deSEric W. Biederman return ret; 175662795deSEric W. Biederman } 176662795deSEric W. Biederman 177662795deSEric W. Biederman struct file_operations proc_maps_operations = { 178662795deSEric W. Biederman .open = maps_open, 179662795deSEric W. Biederman .read = seq_read, 180662795deSEric W. Biederman .llseek = seq_lseek, 181662795deSEric W. Biederman .release = seq_release, 182662795deSEric W. Biederman }; 183662795deSEric W. Biederman 184