xref: /openbmc/linux/fs/proc/task_nommu.c (revision 2fddfeef)
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) {
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 
223662795deSEric W. Biederman 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