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