xref: /openbmc/linux/fs/proc/task_nommu.c (revision 31304c90)
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(&current->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(&current->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(&current->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