xref: /openbmc/linux/fs/proc/task_nommu.c (revision 33e5d769)
11da177e4SLinus Torvalds 
21da177e4SLinus Torvalds #include <linux/mm.h>
31da177e4SLinus Torvalds #include <linux/file.h>
4eb28062fSBryan Wu #include <linux/fdtable.h>
51da177e4SLinus Torvalds #include <linux/mount.h>
65096add8SKees Cook #include <linux/ptrace.h>
71da177e4SLinus Torvalds #include <linux/seq_file.h>
81da177e4SLinus Torvalds #include "internal.h"
91da177e4SLinus Torvalds 
101da177e4SLinus Torvalds /*
111da177e4SLinus Torvalds  * Logic: we've got two memory sums for each process, "shared", and
12025dfdafSFrederik Schwarzer  * "non-shared". Shared memory may get counted more than once, for
131da177e4SLinus Torvalds  * each process that owns it. Non-shared memory is counted
141da177e4SLinus Torvalds  * accurately.
151da177e4SLinus Torvalds  */
16df5f8314SEric W. Biederman void task_mem(struct seq_file *m, struct mm_struct *mm)
171da177e4SLinus Torvalds {
188feae131SDavid Howells 	struct vm_area_struct *vma;
1938f71479SDavid Howells 	struct vm_region *region;
208feae131SDavid Howells 	struct rb_node *p;
2138f71479SDavid Howells 	unsigned long bytes = 0, sbytes = 0, slack = 0, size;
221da177e4SLinus Torvalds 
231da177e4SLinus Torvalds 	down_read(&mm->mmap_sem);
248feae131SDavid Howells 	for (p = rb_first(&mm->mm_rb); p; p = rb_next(p)) {
258feae131SDavid Howells 		vma = rb_entry(p, struct vm_area_struct, vm_rb);
261da177e4SLinus Torvalds 
278feae131SDavid Howells 		bytes += kobjsize(vma);
2838f71479SDavid Howells 
2938f71479SDavid Howells 		region = vma->vm_region;
3038f71479SDavid Howells 		if (region) {
3138f71479SDavid Howells 			size = kobjsize(region);
3238f71479SDavid Howells 			size += region->vm_end - region->vm_start;
331da177e4SLinus Torvalds 		} else {
3438f71479SDavid Howells 			size = vma->vm_end - vma->vm_start;
3538f71479SDavid Howells 		}
3638f71479SDavid Howells 
3738f71479SDavid Howells 		if (atomic_read(&mm->mm_count) > 1 ||
3838f71479SDavid Howells 		    vma->vm_flags & VM_MAYSHARE) {
3938f71479SDavid Howells 			sbytes += size;
4038f71479SDavid Howells 		} else {
4138f71479SDavid Howells 			bytes += size;
4238f71479SDavid Howells 			if (region)
4338f71479SDavid Howells 				slack = region->vm_end - vma->vm_end;
441da177e4SLinus Torvalds 		}
451da177e4SLinus Torvalds 	}
461da177e4SLinus Torvalds 
471da177e4SLinus Torvalds 	if (atomic_read(&mm->mm_count) > 1)
481da177e4SLinus Torvalds 		sbytes += kobjsize(mm);
491da177e4SLinus Torvalds 	else
501da177e4SLinus Torvalds 		bytes += kobjsize(mm);
511da177e4SLinus Torvalds 
521da177e4SLinus Torvalds 	if (current->fs && atomic_read(&current->fs->count) > 1)
531da177e4SLinus Torvalds 		sbytes += kobjsize(current->fs);
541da177e4SLinus Torvalds 	else
551da177e4SLinus Torvalds 		bytes += kobjsize(current->fs);
561da177e4SLinus Torvalds 
571da177e4SLinus Torvalds 	if (current->files && atomic_read(&current->files->count) > 1)
581da177e4SLinus Torvalds 		sbytes += kobjsize(current->files);
591da177e4SLinus Torvalds 	else
601da177e4SLinus Torvalds 		bytes += kobjsize(current->files);
611da177e4SLinus Torvalds 
621da177e4SLinus Torvalds 	if (current->sighand && atomic_read(&current->sighand->count) > 1)
631da177e4SLinus Torvalds 		sbytes += kobjsize(current->sighand);
641da177e4SLinus Torvalds 	else
651da177e4SLinus Torvalds 		bytes += kobjsize(current->sighand);
661da177e4SLinus Torvalds 
671da177e4SLinus Torvalds 	bytes += kobjsize(current); /* includes kernel stack */
681da177e4SLinus Torvalds 
69df5f8314SEric W. Biederman 	seq_printf(m,
701da177e4SLinus Torvalds 		"Mem:\t%8lu bytes\n"
711da177e4SLinus Torvalds 		"Slack:\t%8lu bytes\n"
721da177e4SLinus Torvalds 		"Shared:\t%8lu bytes\n",
731da177e4SLinus Torvalds 		bytes, slack, sbytes);
741da177e4SLinus Torvalds 
751da177e4SLinus Torvalds 	up_read(&mm->mmap_sem);
761da177e4SLinus Torvalds }
771da177e4SLinus Torvalds 
781da177e4SLinus Torvalds unsigned long task_vsize(struct mm_struct *mm)
791da177e4SLinus Torvalds {
808feae131SDavid Howells 	struct vm_area_struct *vma;
818feae131SDavid Howells 	struct rb_node *p;
821da177e4SLinus Torvalds 	unsigned long vsize = 0;
831da177e4SLinus Torvalds 
841da177e4SLinus Torvalds 	down_read(&mm->mmap_sem);
858feae131SDavid Howells 	for (p = rb_first(&mm->mm_rb); p; p = rb_next(p)) {
868feae131SDavid Howells 		vma = rb_entry(p, struct vm_area_struct, vm_rb);
8738f71479SDavid Howells 		vsize += vma->vm_end - vma->vm_start;
881da177e4SLinus Torvalds 	}
891da177e4SLinus Torvalds 	up_read(&mm->mmap_sem);
901da177e4SLinus Torvalds 	return vsize;
911da177e4SLinus Torvalds }
921da177e4SLinus Torvalds 
931da177e4SLinus Torvalds int task_statm(struct mm_struct *mm, int *shared, int *text,
941da177e4SLinus Torvalds 	       int *data, int *resident)
951da177e4SLinus Torvalds {
968feae131SDavid Howells 	struct vm_area_struct *vma;
9738f71479SDavid Howells 	struct vm_region *region;
988feae131SDavid Howells 	struct rb_node *p;
991da177e4SLinus Torvalds 	int size = kobjsize(mm);
1001da177e4SLinus Torvalds 
1011da177e4SLinus Torvalds 	down_read(&mm->mmap_sem);
1028feae131SDavid Howells 	for (p = rb_first(&mm->mm_rb); p; p = rb_next(p)) {
1038feae131SDavid Howells 		vma = rb_entry(p, struct vm_area_struct, vm_rb);
1048feae131SDavid Howells 		size += kobjsize(vma);
10538f71479SDavid Howells 		region = vma->vm_region;
10638f71479SDavid Howells 		if (region) {
10738f71479SDavid Howells 			size += kobjsize(region);
10838f71479SDavid Howells 			size += region->vm_end - region->vm_start;
10938f71479SDavid Howells 		}
1101da177e4SLinus Torvalds 	}
1111da177e4SLinus Torvalds 
1121da177e4SLinus Torvalds 	size += (*text = mm->end_code - mm->start_code);
1131da177e4SLinus Torvalds 	size += (*data = mm->start_stack - mm->start_data);
1141da177e4SLinus Torvalds 	up_read(&mm->mmap_sem);
1151da177e4SLinus Torvalds 	*resident = size;
1161da177e4SLinus Torvalds 	return size;
1171da177e4SLinus Torvalds }
1181da177e4SLinus Torvalds 
1191da177e4SLinus Torvalds /*
1208feae131SDavid Howells  * display a single VMA to a sequenced file
1218feae131SDavid Howells  */
1228feae131SDavid Howells static int nommu_vma_show(struct seq_file *m, struct vm_area_struct *vma)
1238feae131SDavid Howells {
1248feae131SDavid Howells 	unsigned long ino = 0;
1258feae131SDavid Howells 	struct file *file;
1268feae131SDavid Howells 	dev_t dev = 0;
1278feae131SDavid Howells 	int flags, len;
1288feae131SDavid Howells 
1298feae131SDavid Howells 	flags = vma->vm_flags;
1308feae131SDavid Howells 	file = vma->vm_file;
1318feae131SDavid Howells 
1328feae131SDavid Howells 	if (file) {
1338feae131SDavid Howells 		struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
1348feae131SDavid Howells 		dev = inode->i_sb->s_dev;
1358feae131SDavid Howells 		ino = inode->i_ino;
1368feae131SDavid Howells 	}
1378feae131SDavid Howells 
1388feae131SDavid Howells 	seq_printf(m,
13933e5d769SDavid Howells 		   "%08lx-%08lx %c%c%c%c %08llx %02x:%02x %lu %n",
1408feae131SDavid Howells 		   vma->vm_start,
1418feae131SDavid Howells 		   vma->vm_end,
1428feae131SDavid Howells 		   flags & VM_READ ? 'r' : '-',
1438feae131SDavid Howells 		   flags & VM_WRITE ? 'w' : '-',
1448feae131SDavid Howells 		   flags & VM_EXEC ? 'x' : '-',
1458feae131SDavid Howells 		   flags & VM_MAYSHARE ? flags & VM_SHARED ? 'S' : 's' : 'p',
14633e5d769SDavid Howells 		   (unsigned long long) vma->vm_pgoff << PAGE_SHIFT,
1478feae131SDavid Howells 		   MAJOR(dev), MINOR(dev), ino, &len);
1488feae131SDavid Howells 
1498feae131SDavid Howells 	if (file) {
1508feae131SDavid Howells 		len = 25 + sizeof(void *) * 6 - len;
1518feae131SDavid Howells 		if (len < 1)
1528feae131SDavid Howells 			len = 1;
1538feae131SDavid Howells 		seq_printf(m, "%*c", len, ' ');
1548feae131SDavid Howells 		seq_path(m, &file->f_path, "");
1558feae131SDavid Howells 	}
1568feae131SDavid Howells 
1578feae131SDavid Howells 	seq_putc(m, '\n');
1588feae131SDavid Howells 	return 0;
1598feae131SDavid Howells }
1608feae131SDavid Howells 
1618feae131SDavid Howells /*
162dbf8685cSDavid Howells  * display mapping lines for a particular process's /proc/pid/maps
1631da177e4SLinus Torvalds  */
1648feae131SDavid Howells static int show_map(struct seq_file *m, void *_p)
1651da177e4SLinus Torvalds {
1668feae131SDavid Howells 	struct rb_node *p = _p;
1675096add8SKees Cook 
1688feae131SDavid Howells 	return nommu_vma_show(m, rb_entry(p, struct vm_area_struct, vm_rb));
1691da177e4SLinus Torvalds }
170dbf8685cSDavid Howells 
1711da177e4SLinus Torvalds static void *m_start(struct seq_file *m, loff_t *pos)
1721da177e4SLinus Torvalds {
173dbf8685cSDavid Howells 	struct proc_maps_private *priv = m->private;
174dbf8685cSDavid Howells 	struct mm_struct *mm;
1758feae131SDavid Howells 	struct rb_node *p;
176dbf8685cSDavid Howells 	loff_t n = *pos;
177dbf8685cSDavid Howells 
178dbf8685cSDavid Howells 	/* pin the task and mm whilst we play with them */
179dbf8685cSDavid Howells 	priv->task = get_pid_task(priv->pid, PIDTYPE_PID);
180dbf8685cSDavid Howells 	if (!priv->task)
181dbf8685cSDavid Howells 		return NULL;
182dbf8685cSDavid Howells 
183831830b5SAl Viro 	mm = mm_for_maps(priv->task);
184dbf8685cSDavid Howells 	if (!mm) {
185dbf8685cSDavid Howells 		put_task_struct(priv->task);
186dbf8685cSDavid Howells 		priv->task = NULL;
1871da177e4SLinus Torvalds 		return NULL;
1881da177e4SLinus Torvalds 	}
189dbf8685cSDavid Howells 
190dbf8685cSDavid Howells 	/* start from the Nth VMA */
1918feae131SDavid Howells 	for (p = rb_first(&mm->mm_rb); p; p = rb_next(p))
192dbf8685cSDavid Howells 		if (n-- == 0)
1938feae131SDavid Howells 			return p;
1941da177e4SLinus Torvalds 	return NULL;
1951da177e4SLinus Torvalds }
196dbf8685cSDavid Howells 
197dbf8685cSDavid Howells static void m_stop(struct seq_file *m, void *_vml)
198dbf8685cSDavid Howells {
199dbf8685cSDavid Howells 	struct proc_maps_private *priv = m->private;
200dbf8685cSDavid Howells 
201dbf8685cSDavid Howells 	if (priv->task) {
202dbf8685cSDavid Howells 		struct mm_struct *mm = priv->task->mm;
203dbf8685cSDavid Howells 		up_read(&mm->mmap_sem);
204dbf8685cSDavid Howells 		mmput(mm);
205dbf8685cSDavid Howells 		put_task_struct(priv->task);
206dbf8685cSDavid Howells 	}
207dbf8685cSDavid Howells }
208dbf8685cSDavid Howells 
2098feae131SDavid Howells static void *m_next(struct seq_file *m, void *_p, loff_t *pos)
210dbf8685cSDavid Howells {
2118feae131SDavid Howells 	struct rb_node *p = _p;
212dbf8685cSDavid Howells 
213dbf8685cSDavid Howells 	(*pos)++;
2148feae131SDavid Howells 	return p ? rb_next(p) : NULL;
215dbf8685cSDavid Howells }
216dbf8685cSDavid Howells 
21703a44825SJan Engelhardt static const struct seq_operations proc_pid_maps_ops = {
2181da177e4SLinus Torvalds 	.start	= m_start,
2191da177e4SLinus Torvalds 	.next	= m_next,
2201da177e4SLinus Torvalds 	.stop	= m_stop,
2211da177e4SLinus Torvalds 	.show	= show_map
2221da177e4SLinus Torvalds };
223662795deSEric W. Biederman 
224662795deSEric W. Biederman static int maps_open(struct inode *inode, struct file *file)
225662795deSEric W. Biederman {
226dbf8685cSDavid Howells 	struct proc_maps_private *priv;
227dbf8685cSDavid Howells 	int ret = -ENOMEM;
228dbf8685cSDavid Howells 
229dbf8685cSDavid Howells 	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
230dbf8685cSDavid Howells 	if (priv) {
231dbf8685cSDavid Howells 		priv->pid = proc_pid(inode);
232dbf8685cSDavid Howells 		ret = seq_open(file, &proc_pid_maps_ops);
233662795deSEric W. Biederman 		if (!ret) {
234662795deSEric W. Biederman 			struct seq_file *m = file->private_data;
235dbf8685cSDavid Howells 			m->private = priv;
236dbf8685cSDavid Howells 		} else {
237dbf8685cSDavid Howells 			kfree(priv);
238dbf8685cSDavid Howells 		}
239662795deSEric W. Biederman 	}
240662795deSEric W. Biederman 	return ret;
241662795deSEric W. Biederman }
242662795deSEric W. Biederman 
24300977a59SArjan van de Ven const struct file_operations proc_maps_operations = {
244662795deSEric W. Biederman 	.open		= maps_open,
245662795deSEric W. Biederman 	.read		= seq_read,
246662795deSEric W. Biederman 	.llseek		= seq_lseek,
247dbf8685cSDavid Howells 	.release	= seq_release_private,
248662795deSEric W. Biederman };
249662795deSEric W. Biederman 
250