xref: /openbmc/linux/fs/proc/task_nommu.c (revision 4c967291)
11da177e4SLinus Torvalds 
21da177e4SLinus Torvalds #include <linux/mm.h>
31da177e4SLinus Torvalds #include <linux/file.h>
4eb28062fSBryan Wu #include <linux/fdtable.h>
55ad4e53bSAl Viro #include <linux/fs_struct.h>
61da177e4SLinus Torvalds #include <linux/mount.h>
75096add8SKees Cook #include <linux/ptrace.h>
81da177e4SLinus Torvalds #include <linux/seq_file.h>
91da177e4SLinus Torvalds #include "internal.h"
101da177e4SLinus Torvalds 
111da177e4SLinus Torvalds /*
121da177e4SLinus Torvalds  * Logic: we've got two memory sums for each process, "shared", and
13025dfdafSFrederik Schwarzer  * "non-shared". Shared memory may get counted more than once, for
141da177e4SLinus Torvalds  * each process that owns it. Non-shared memory is counted
151da177e4SLinus Torvalds  * accurately.
161da177e4SLinus Torvalds  */
17df5f8314SEric W. Biederman void task_mem(struct seq_file *m, struct mm_struct *mm)
181da177e4SLinus Torvalds {
198feae131SDavid Howells 	struct vm_area_struct *vma;
2038f71479SDavid Howells 	struct vm_region *region;
218feae131SDavid Howells 	struct rb_node *p;
2238f71479SDavid Howells 	unsigned long bytes = 0, sbytes = 0, slack = 0, size;
231da177e4SLinus Torvalds 
241da177e4SLinus Torvalds 	down_read(&mm->mmap_sem);
258feae131SDavid Howells 	for (p = rb_first(&mm->mm_rb); p; p = rb_next(p)) {
268feae131SDavid Howells 		vma = rb_entry(p, struct vm_area_struct, vm_rb);
271da177e4SLinus Torvalds 
288feae131SDavid Howells 		bytes += kobjsize(vma);
2938f71479SDavid Howells 
3038f71479SDavid Howells 		region = vma->vm_region;
3138f71479SDavid Howells 		if (region) {
3238f71479SDavid Howells 			size = kobjsize(region);
3338f71479SDavid Howells 			size += region->vm_end - region->vm_start;
341da177e4SLinus Torvalds 		} else {
3538f71479SDavid Howells 			size = vma->vm_end - vma->vm_start;
3638f71479SDavid Howells 		}
3738f71479SDavid Howells 
3838f71479SDavid Howells 		if (atomic_read(&mm->mm_count) > 1 ||
3938f71479SDavid Howells 		    vma->vm_flags & VM_MAYSHARE) {
4038f71479SDavid Howells 			sbytes += size;
4138f71479SDavid Howells 		} else {
4238f71479SDavid Howells 			bytes += size;
4338f71479SDavid Howells 			if (region)
4438f71479SDavid Howells 				slack = region->vm_end - vma->vm_end;
451da177e4SLinus Torvalds 		}
461da177e4SLinus Torvalds 	}
471da177e4SLinus Torvalds 
481da177e4SLinus Torvalds 	if (atomic_read(&mm->mm_count) > 1)
491da177e4SLinus Torvalds 		sbytes += kobjsize(mm);
501da177e4SLinus Torvalds 	else
511da177e4SLinus Torvalds 		bytes += kobjsize(mm);
521da177e4SLinus Torvalds 
53498052bbSAl Viro 	if (current->fs && current->fs->users > 1)
541da177e4SLinus Torvalds 		sbytes += kobjsize(current->fs);
551da177e4SLinus Torvalds 	else
561da177e4SLinus Torvalds 		bytes += kobjsize(current->fs);
571da177e4SLinus Torvalds 
581da177e4SLinus Torvalds 	if (current->files && atomic_read(&current->files->count) > 1)
591da177e4SLinus Torvalds 		sbytes += kobjsize(current->files);
601da177e4SLinus Torvalds 	else
611da177e4SLinus Torvalds 		bytes += kobjsize(current->files);
621da177e4SLinus Torvalds 
631da177e4SLinus Torvalds 	if (current->sighand && atomic_read(&current->sighand->count) > 1)
641da177e4SLinus Torvalds 		sbytes += kobjsize(current->sighand);
651da177e4SLinus Torvalds 	else
661da177e4SLinus Torvalds 		bytes += kobjsize(current->sighand);
671da177e4SLinus Torvalds 
681da177e4SLinus Torvalds 	bytes += kobjsize(current); /* includes kernel stack */
691da177e4SLinus Torvalds 
70df5f8314SEric W. Biederman 	seq_printf(m,
711da177e4SLinus Torvalds 		"Mem:\t%8lu bytes\n"
721da177e4SLinus Torvalds 		"Slack:\t%8lu bytes\n"
731da177e4SLinus Torvalds 		"Shared:\t%8lu bytes\n",
741da177e4SLinus Torvalds 		bytes, slack, sbytes);
751da177e4SLinus Torvalds 
761da177e4SLinus Torvalds 	up_read(&mm->mmap_sem);
771da177e4SLinus Torvalds }
781da177e4SLinus Torvalds 
791da177e4SLinus Torvalds unsigned long task_vsize(struct mm_struct *mm)
801da177e4SLinus Torvalds {
818feae131SDavid Howells 	struct vm_area_struct *vma;
828feae131SDavid Howells 	struct rb_node *p;
831da177e4SLinus Torvalds 	unsigned long vsize = 0;
841da177e4SLinus Torvalds 
851da177e4SLinus Torvalds 	down_read(&mm->mmap_sem);
868feae131SDavid Howells 	for (p = rb_first(&mm->mm_rb); p; p = rb_next(p)) {
878feae131SDavid Howells 		vma = rb_entry(p, struct vm_area_struct, vm_rb);
8838f71479SDavid Howells 		vsize += vma->vm_end - vma->vm_start;
891da177e4SLinus Torvalds 	}
901da177e4SLinus Torvalds 	up_read(&mm->mmap_sem);
911da177e4SLinus Torvalds 	return vsize;
921da177e4SLinus Torvalds }
931da177e4SLinus Torvalds 
941da177e4SLinus Torvalds int task_statm(struct mm_struct *mm, int *shared, int *text,
951da177e4SLinus Torvalds 	       int *data, int *resident)
961da177e4SLinus Torvalds {
978feae131SDavid Howells 	struct vm_area_struct *vma;
9838f71479SDavid Howells 	struct vm_region *region;
998feae131SDavid Howells 	struct rb_node *p;
1001da177e4SLinus Torvalds 	int size = kobjsize(mm);
1011da177e4SLinus Torvalds 
1021da177e4SLinus Torvalds 	down_read(&mm->mmap_sem);
1038feae131SDavid Howells 	for (p = rb_first(&mm->mm_rb); p; p = rb_next(p)) {
1048feae131SDavid Howells 		vma = rb_entry(p, struct vm_area_struct, vm_rb);
1058feae131SDavid Howells 		size += kobjsize(vma);
10638f71479SDavid Howells 		region = vma->vm_region;
10738f71479SDavid Howells 		if (region) {
10838f71479SDavid Howells 			size += kobjsize(region);
10938f71479SDavid Howells 			size += region->vm_end - region->vm_start;
11038f71479SDavid Howells 		}
1111da177e4SLinus Torvalds 	}
1121da177e4SLinus Torvalds 
1131da177e4SLinus Torvalds 	size += (*text = mm->end_code - mm->start_code);
1141da177e4SLinus Torvalds 	size += (*data = mm->start_stack - mm->start_data);
1151da177e4SLinus Torvalds 	up_read(&mm->mmap_sem);
1161da177e4SLinus Torvalds 	*resident = size;
1171da177e4SLinus Torvalds 	return size;
1181da177e4SLinus Torvalds }
1191da177e4SLinus Torvalds 
1201da177e4SLinus Torvalds /*
1218feae131SDavid Howells  * display a single VMA to a sequenced file
1228feae131SDavid Howells  */
1238feae131SDavid Howells static int nommu_vma_show(struct seq_file *m, struct vm_area_struct *vma)
1248feae131SDavid Howells {
1258feae131SDavid Howells 	unsigned long ino = 0;
1268feae131SDavid Howells 	struct file *file;
1278feae131SDavid Howells 	dev_t dev = 0;
1288feae131SDavid Howells 	int flags, len;
1296260a4b0SKAMEZAWA Hiroyuki 	unsigned long long pgoff = 0;
1308feae131SDavid Howells 
1318feae131SDavid Howells 	flags = vma->vm_flags;
1328feae131SDavid Howells 	file = vma->vm_file;
1338feae131SDavid Howells 
1348feae131SDavid Howells 	if (file) {
1358feae131SDavid Howells 		struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
1368feae131SDavid Howells 		dev = inode->i_sb->s_dev;
1378feae131SDavid Howells 		ino = inode->i_ino;
1384c967291SNobuhiro Iwamatsu 		pgoff = (loff_t)vma->vm_pgoff << PAGE_SHIFT;
1398feae131SDavid Howells 	}
1408feae131SDavid Howells 
1418feae131SDavid Howells 	seq_printf(m,
14233e5d769SDavid Howells 		   "%08lx-%08lx %c%c%c%c %08llx %02x:%02x %lu %n",
1438feae131SDavid Howells 		   vma->vm_start,
1448feae131SDavid Howells 		   vma->vm_end,
1458feae131SDavid Howells 		   flags & VM_READ ? 'r' : '-',
1468feae131SDavid Howells 		   flags & VM_WRITE ? 'w' : '-',
1478feae131SDavid Howells 		   flags & VM_EXEC ? 'x' : '-',
1488feae131SDavid Howells 		   flags & VM_MAYSHARE ? flags & VM_SHARED ? 'S' : 's' : 'p',
1496260a4b0SKAMEZAWA Hiroyuki 		   pgoff,
1508feae131SDavid Howells 		   MAJOR(dev), MINOR(dev), ino, &len);
1518feae131SDavid Howells 
1528feae131SDavid Howells 	if (file) {
1538feae131SDavid Howells 		len = 25 + sizeof(void *) * 6 - len;
1548feae131SDavid Howells 		if (len < 1)
1558feae131SDavid Howells 			len = 1;
1568feae131SDavid Howells 		seq_printf(m, "%*c", len, ' ');
1578feae131SDavid Howells 		seq_path(m, &file->f_path, "");
1588feae131SDavid Howells 	}
1598feae131SDavid Howells 
1608feae131SDavid Howells 	seq_putc(m, '\n');
1618feae131SDavid Howells 	return 0;
1628feae131SDavid Howells }
1638feae131SDavid Howells 
1648feae131SDavid Howells /*
165dbf8685cSDavid Howells  * display mapping lines for a particular process's /proc/pid/maps
1661da177e4SLinus Torvalds  */
1678feae131SDavid Howells static int show_map(struct seq_file *m, void *_p)
1681da177e4SLinus Torvalds {
1698feae131SDavid Howells 	struct rb_node *p = _p;
1705096add8SKees Cook 
1718feae131SDavid Howells 	return nommu_vma_show(m, rb_entry(p, struct vm_area_struct, vm_rb));
1721da177e4SLinus Torvalds }
173dbf8685cSDavid Howells 
1741da177e4SLinus Torvalds static void *m_start(struct seq_file *m, loff_t *pos)
1751da177e4SLinus Torvalds {
176dbf8685cSDavid Howells 	struct proc_maps_private *priv = m->private;
177dbf8685cSDavid Howells 	struct mm_struct *mm;
1788feae131SDavid Howells 	struct rb_node *p;
179dbf8685cSDavid Howells 	loff_t n = *pos;
180dbf8685cSDavid Howells 
181dbf8685cSDavid Howells 	/* pin the task and mm whilst we play with them */
182dbf8685cSDavid Howells 	priv->task = get_pid_task(priv->pid, PIDTYPE_PID);
183dbf8685cSDavid Howells 	if (!priv->task)
184dbf8685cSDavid Howells 		return NULL;
185dbf8685cSDavid Howells 
186831830b5SAl Viro 	mm = mm_for_maps(priv->task);
187dbf8685cSDavid Howells 	if (!mm) {
188dbf8685cSDavid Howells 		put_task_struct(priv->task);
189dbf8685cSDavid Howells 		priv->task = NULL;
1901da177e4SLinus Torvalds 		return NULL;
1911da177e4SLinus Torvalds 	}
192dbf8685cSDavid Howells 
193dbf8685cSDavid Howells 	/* start from the Nth VMA */
1948feae131SDavid Howells 	for (p = rb_first(&mm->mm_rb); p; p = rb_next(p))
195dbf8685cSDavid Howells 		if (n-- == 0)
1968feae131SDavid Howells 			return p;
1971da177e4SLinus Torvalds 	return NULL;
1981da177e4SLinus Torvalds }
199dbf8685cSDavid Howells 
200dbf8685cSDavid Howells static void m_stop(struct seq_file *m, void *_vml)
201dbf8685cSDavid Howells {
202dbf8685cSDavid Howells 	struct proc_maps_private *priv = m->private;
203dbf8685cSDavid Howells 
204dbf8685cSDavid Howells 	if (priv->task) {
205dbf8685cSDavid Howells 		struct mm_struct *mm = priv->task->mm;
206dbf8685cSDavid Howells 		up_read(&mm->mmap_sem);
207dbf8685cSDavid Howells 		mmput(mm);
208dbf8685cSDavid Howells 		put_task_struct(priv->task);
209dbf8685cSDavid Howells 	}
210dbf8685cSDavid Howells }
211dbf8685cSDavid Howells 
2128feae131SDavid Howells static void *m_next(struct seq_file *m, void *_p, loff_t *pos)
213dbf8685cSDavid Howells {
2148feae131SDavid Howells 	struct rb_node *p = _p;
215dbf8685cSDavid Howells 
216dbf8685cSDavid Howells 	(*pos)++;
2178feae131SDavid Howells 	return p ? rb_next(p) : NULL;
218dbf8685cSDavid Howells }
219dbf8685cSDavid Howells 
22003a44825SJan Engelhardt static const struct seq_operations proc_pid_maps_ops = {
2211da177e4SLinus Torvalds 	.start	= m_start,
2221da177e4SLinus Torvalds 	.next	= m_next,
2231da177e4SLinus Torvalds 	.stop	= m_stop,
2241da177e4SLinus Torvalds 	.show	= show_map
2251da177e4SLinus Torvalds };
226662795deSEric W. Biederman 
227662795deSEric W. Biederman static int maps_open(struct inode *inode, struct file *file)
228662795deSEric W. Biederman {
229dbf8685cSDavid Howells 	struct proc_maps_private *priv;
230dbf8685cSDavid Howells 	int ret = -ENOMEM;
231dbf8685cSDavid Howells 
232dbf8685cSDavid Howells 	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
233dbf8685cSDavid Howells 	if (priv) {
234dbf8685cSDavid Howells 		priv->pid = proc_pid(inode);
235dbf8685cSDavid Howells 		ret = seq_open(file, &proc_pid_maps_ops);
236662795deSEric W. Biederman 		if (!ret) {
237662795deSEric W. Biederman 			struct seq_file *m = file->private_data;
238dbf8685cSDavid Howells 			m->private = priv;
239dbf8685cSDavid Howells 		} else {
240dbf8685cSDavid Howells 			kfree(priv);
241dbf8685cSDavid Howells 		}
242662795deSEric W. Biederman 	}
243662795deSEric W. Biederman 	return ret;
244662795deSEric W. Biederman }
245662795deSEric W. Biederman 
24600977a59SArjan van de Ven const struct file_operations proc_maps_operations = {
247662795deSEric W. Biederman 	.open		= maps_open,
248662795deSEric W. Biederman 	.read		= seq_read,
249662795deSEric W. Biederman 	.llseek		= seq_lseek,
250dbf8685cSDavid Howells 	.release	= seq_release_private,
251662795deSEric W. Biederman };
252662795deSEric W. Biederman 
253