aboutsummaryrefslogtreecommitdiffstats
path: root/fs/proc
diff options
context:
space:
mode:
authorJeff Garzik <jgarzik@pobox.com>2005-09-08 05:43:49 -0400
committerJeff Garzik <jgarzik@pobox.com>2005-09-08 05:43:49 -0400
commit1d6ae775d7a948c9575658eb41184fd2e506c0df (patch)
tree8128a28e89d82f13bb8e3a2160382240c66e2816 /fs/proc
parent739cdbf1d8f0739b80035b80d69d871e33749b86 (diff)
parentcaf39e87cc1182f7dae84eefc43ca14d54c78ef9 (diff)
Merge /spare/repo/linux-2.6/
Diffstat (limited to 'fs/proc')
-rw-r--r--fs/proc/base.c159
-rw-r--r--fs/proc/generic.c13
-rw-r--r--fs/proc/task_mmu.c357
3 files changed, 443 insertions, 86 deletions
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 491f2d9f89ac..84751f3f52d5 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -11,6 +11,40 @@
11 * go into icache. We cache the reference to task_struct upon lookup too. 11 * go into icache. We cache the reference to task_struct upon lookup too.
12 * Eventually it should become a filesystem in its own. We don't use the 12 * Eventually it should become a filesystem in its own. We don't use the
13 * rest of procfs anymore. 13 * rest of procfs anymore.
14 *
15 *
16 * Changelog:
17 * 17-Jan-2005
18 * Allan Bezerra
19 * Bruna Moreira <bruna.moreira@indt.org.br>
20 * Edjard Mota <edjard.mota@indt.org.br>
21 * Ilias Biris <ilias.biris@indt.org.br>
22 * Mauricio Lin <mauricio.lin@indt.org.br>
23 *
24 * Embedded Linux Lab - 10LE Instituto Nokia de Tecnologia - INdT
25 *
26 * A new process specific entry (smaps) included in /proc. It shows the
27 * size of rss for each memory area. The maps entry lacks information
28 * about physical memory size (rss) for each mapped file, i.e.,
29 * rss information for executables and library files.
30 * This additional information is useful for any tools that need to know
31 * about physical memory consumption for a process specific library.
32 *
33 * Changelog:
34 * 21-Feb-2005
35 * Embedded Linux Lab - 10LE Instituto Nokia de Tecnologia - INdT
36 * Pud inclusion in the page table walking.
37 *
38 * ChangeLog:
39 * 10-Mar-2005
40 * 10LE Instituto Nokia de Tecnologia - INdT:
41 * A better way to walks through the page table as suggested by Hugh Dickins.
42 *
43 * Simo Piiroinen <simo.piiroinen@nokia.com>:
44 * Smaps information related to shared, private, clean and dirty pages.
45 *
46 * Paul Mundt <paul.mundt@nokia.com>:
47 * Overall revision about smaps.
14 */ 48 */
15 49
16#include <asm/uaccess.h> 50#include <asm/uaccess.h>
@@ -65,8 +99,10 @@ enum pid_directory_inos {
65 PROC_TGID_STAT, 99 PROC_TGID_STAT,
66 PROC_TGID_STATM, 100 PROC_TGID_STATM,
67 PROC_TGID_MAPS, 101 PROC_TGID_MAPS,
102 PROC_TGID_NUMA_MAPS,
68 PROC_TGID_MOUNTS, 103 PROC_TGID_MOUNTS,
69 PROC_TGID_WCHAN, 104 PROC_TGID_WCHAN,
105 PROC_TGID_SMAPS,
70#ifdef CONFIG_SCHEDSTATS 106#ifdef CONFIG_SCHEDSTATS
71 PROC_TGID_SCHEDSTAT, 107 PROC_TGID_SCHEDSTAT,
72#endif 108#endif
@@ -83,7 +119,6 @@ enum pid_directory_inos {
83#ifdef CONFIG_AUDITSYSCALL 119#ifdef CONFIG_AUDITSYSCALL
84 PROC_TGID_LOGINUID, 120 PROC_TGID_LOGINUID,
85#endif 121#endif
86 PROC_TGID_FD_DIR,
87 PROC_TGID_OOM_SCORE, 122 PROC_TGID_OOM_SCORE,
88 PROC_TGID_OOM_ADJUST, 123 PROC_TGID_OOM_ADJUST,
89 PROC_TID_INO, 124 PROC_TID_INO,
@@ -102,8 +137,10 @@ enum pid_directory_inos {
102 PROC_TID_STAT, 137 PROC_TID_STAT,
103 PROC_TID_STATM, 138 PROC_TID_STATM,
104 PROC_TID_MAPS, 139 PROC_TID_MAPS,
140 PROC_TID_NUMA_MAPS,
105 PROC_TID_MOUNTS, 141 PROC_TID_MOUNTS,
106 PROC_TID_WCHAN, 142 PROC_TID_WCHAN,
143 PROC_TID_SMAPS,
107#ifdef CONFIG_SCHEDSTATS 144#ifdef CONFIG_SCHEDSTATS
108 PROC_TID_SCHEDSTAT, 145 PROC_TID_SCHEDSTAT,
109#endif 146#endif
@@ -120,9 +157,11 @@ enum pid_directory_inos {
120#ifdef CONFIG_AUDITSYSCALL 157#ifdef CONFIG_AUDITSYSCALL
121 PROC_TID_LOGINUID, 158 PROC_TID_LOGINUID,
122#endif 159#endif
123 PROC_TID_FD_DIR = 0x8000, /* 0x8000-0xffff */
124 PROC_TID_OOM_SCORE, 160 PROC_TID_OOM_SCORE,
125 PROC_TID_OOM_ADJUST, 161 PROC_TID_OOM_ADJUST,
162
163 /* Add new entries before this */
164 PROC_TID_FD_DIR = 0x8000, /* 0x8000-0xffff */
126}; 165};
127 166
128struct pid_entry { 167struct pid_entry {
@@ -144,6 +183,9 @@ static struct pid_entry tgid_base_stuff[] = {
144 E(PROC_TGID_STAT, "stat", S_IFREG|S_IRUGO), 183 E(PROC_TGID_STAT, "stat", S_IFREG|S_IRUGO),
145 E(PROC_TGID_STATM, "statm", S_IFREG|S_IRUGO), 184 E(PROC_TGID_STATM, "statm", S_IFREG|S_IRUGO),
146 E(PROC_TGID_MAPS, "maps", S_IFREG|S_IRUGO), 185 E(PROC_TGID_MAPS, "maps", S_IFREG|S_IRUGO),
186#ifdef CONFIG_NUMA
187 E(PROC_TGID_NUMA_MAPS, "numa_maps", S_IFREG|S_IRUGO),
188#endif
147 E(PROC_TGID_MEM, "mem", S_IFREG|S_IRUSR|S_IWUSR), 189 E(PROC_TGID_MEM, "mem", S_IFREG|S_IRUSR|S_IWUSR),
148#ifdef CONFIG_SECCOMP 190#ifdef CONFIG_SECCOMP
149 E(PROC_TGID_SECCOMP, "seccomp", S_IFREG|S_IRUSR|S_IWUSR), 191 E(PROC_TGID_SECCOMP, "seccomp", S_IFREG|S_IRUSR|S_IWUSR),
@@ -152,6 +194,7 @@ static struct pid_entry tgid_base_stuff[] = {
152 E(PROC_TGID_ROOT, "root", S_IFLNK|S_IRWXUGO), 194 E(PROC_TGID_ROOT, "root", S_IFLNK|S_IRWXUGO),
153 E(PROC_TGID_EXE, "exe", S_IFLNK|S_IRWXUGO), 195 E(PROC_TGID_EXE, "exe", S_IFLNK|S_IRWXUGO),
154 E(PROC_TGID_MOUNTS, "mounts", S_IFREG|S_IRUGO), 196 E(PROC_TGID_MOUNTS, "mounts", S_IFREG|S_IRUGO),
197 E(PROC_TGID_SMAPS, "smaps", S_IFREG|S_IRUGO),
155#ifdef CONFIG_SECURITY 198#ifdef CONFIG_SECURITY
156 E(PROC_TGID_ATTR, "attr", S_IFDIR|S_IRUGO|S_IXUGO), 199 E(PROC_TGID_ATTR, "attr", S_IFDIR|S_IRUGO|S_IXUGO),
157#endif 200#endif
@@ -180,6 +223,9 @@ static struct pid_entry tid_base_stuff[] = {
180 E(PROC_TID_STAT, "stat", S_IFREG|S_IRUGO), 223 E(PROC_TID_STAT, "stat", S_IFREG|S_IRUGO),
181 E(PROC_TID_STATM, "statm", S_IFREG|S_IRUGO), 224 E(PROC_TID_STATM, "statm", S_IFREG|S_IRUGO),
182 E(PROC_TID_MAPS, "maps", S_IFREG|S_IRUGO), 225 E(PROC_TID_MAPS, "maps", S_IFREG|S_IRUGO),
226#ifdef CONFIG_NUMA
227 E(PROC_TID_NUMA_MAPS, "numa_maps", S_IFREG|S_IRUGO),
228#endif
183 E(PROC_TID_MEM, "mem", S_IFREG|S_IRUSR|S_IWUSR), 229 E(PROC_TID_MEM, "mem", S_IFREG|S_IRUSR|S_IWUSR),
184#ifdef CONFIG_SECCOMP 230#ifdef CONFIG_SECCOMP
185 E(PROC_TID_SECCOMP, "seccomp", S_IFREG|S_IRUSR|S_IWUSR), 231 E(PROC_TID_SECCOMP, "seccomp", S_IFREG|S_IRUSR|S_IWUSR),
@@ -188,6 +234,7 @@ static struct pid_entry tid_base_stuff[] = {
188 E(PROC_TID_ROOT, "root", S_IFLNK|S_IRWXUGO), 234 E(PROC_TID_ROOT, "root", S_IFLNK|S_IRWXUGO),
189 E(PROC_TID_EXE, "exe", S_IFLNK|S_IRWXUGO), 235 E(PROC_TID_EXE, "exe", S_IFLNK|S_IRWXUGO),
190 E(PROC_TID_MOUNTS, "mounts", S_IFREG|S_IRUGO), 236 E(PROC_TID_MOUNTS, "mounts", S_IFREG|S_IRUGO),
237 E(PROC_TID_SMAPS, "smaps", S_IFREG|S_IRUGO),
191#ifdef CONFIG_SECURITY 238#ifdef CONFIG_SECURITY
192 E(PROC_TID_ATTR, "attr", S_IFDIR|S_IRUGO|S_IXUGO), 239 E(PROC_TID_ATTR, "attr", S_IFDIR|S_IRUGO|S_IXUGO),
193#endif 240#endif
@@ -251,15 +298,21 @@ static int proc_fd_link(struct inode *inode, struct dentry **dentry, struct vfsm
251 return -ENOENT; 298 return -ENOENT;
252} 299}
253 300
254static int proc_cwd_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt) 301static struct fs_struct *get_fs_struct(struct task_struct *task)
255{ 302{
256 struct fs_struct *fs; 303 struct fs_struct *fs;
257 int result = -ENOENT; 304 task_lock(task);
258 task_lock(proc_task(inode)); 305 fs = task->fs;
259 fs = proc_task(inode)->fs;
260 if(fs) 306 if(fs)
261 atomic_inc(&fs->count); 307 atomic_inc(&fs->count);
262 task_unlock(proc_task(inode)); 308 task_unlock(task);
309 return fs;
310}
311
312static int proc_cwd_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt)
313{
314 struct fs_struct *fs = get_fs_struct(proc_task(inode));
315 int result = -ENOENT;
263 if (fs) { 316 if (fs) {
264 read_lock(&fs->lock); 317 read_lock(&fs->lock);
265 *mnt = mntget(fs->pwdmnt); 318 *mnt = mntget(fs->pwdmnt);
@@ -273,13 +326,8 @@ static int proc_cwd_link(struct inode *inode, struct dentry **dentry, struct vfs
273 326
274static int proc_root_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt) 327static int proc_root_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt)
275{ 328{
276 struct fs_struct *fs; 329 struct fs_struct *fs = get_fs_struct(proc_task(inode));
277 int result = -ENOENT; 330 int result = -ENOENT;
278 task_lock(proc_task(inode));
279 fs = proc_task(inode)->fs;
280 if(fs)
281 atomic_inc(&fs->count);
282 task_unlock(proc_task(inode));
283 if (fs) { 331 if (fs) {
284 read_lock(&fs->lock); 332 read_lock(&fs->lock);
285 *mnt = mntget(fs->rootmnt); 333 *mnt = mntget(fs->rootmnt);
@@ -298,33 +346,6 @@ static int proc_root_link(struct inode *inode, struct dentry **dentry, struct vf
298 (task->state == TASK_STOPPED || task->state == TASK_TRACED) && \ 346 (task->state == TASK_STOPPED || task->state == TASK_TRACED) && \
299 security_ptrace(current,task) == 0)) 347 security_ptrace(current,task) == 0))
300 348
301static int may_ptrace_attach(struct task_struct *task)
302{
303 int retval = 0;
304
305 task_lock(task);
306
307 if (!task->mm)
308 goto out;
309 if (((current->uid != task->euid) ||
310 (current->uid != task->suid) ||
311 (current->uid != task->uid) ||
312 (current->gid != task->egid) ||
313 (current->gid != task->sgid) ||
314 (current->gid != task->gid)) && !capable(CAP_SYS_PTRACE))
315 goto out;
316 rmb();
317 if (task->mm->dumpable != 1 && !capable(CAP_SYS_PTRACE))
318 goto out;
319 if (security_ptrace(current, task))
320 goto out;
321
322 retval = 1;
323out:
324 task_unlock(task);
325 return retval;
326}
327
328static int proc_pid_environ(struct task_struct *task, char * buffer) 349static int proc_pid_environ(struct task_struct *task, char * buffer)
329{ 350{
330 int res = 0; 351 int res = 0;
@@ -334,7 +355,7 @@ static int proc_pid_environ(struct task_struct *task, char * buffer)
334 if (len > PAGE_SIZE) 355 if (len > PAGE_SIZE)
335 len = PAGE_SIZE; 356 len = PAGE_SIZE;
336 res = access_process_vm(task, mm->env_start, buffer, len, 0); 357 res = access_process_vm(task, mm->env_start, buffer, len, 0);
337 if (!may_ptrace_attach(task)) 358 if (!ptrace_may_attach(task))
338 res = -ESRCH; 359 res = -ESRCH;
339 mmput(mm); 360 mmput(mm);
340 } 361 }
@@ -515,6 +536,46 @@ static struct file_operations proc_maps_operations = {
515 .release = seq_release, 536 .release = seq_release,
516}; 537};
517 538
539#ifdef CONFIG_NUMA
540extern struct seq_operations proc_pid_numa_maps_op;
541static int numa_maps_open(struct inode *inode, struct file *file)
542{
543 struct task_struct *task = proc_task(inode);
544 int ret = seq_open(file, &proc_pid_numa_maps_op);
545 if (!ret) {
546 struct seq_file *m = file->private_data;
547 m->private = task;
548 }
549 return ret;
550}
551
552static struct file_operations proc_numa_maps_operations = {
553 .open = numa_maps_open,
554 .read = seq_read,
555 .llseek = seq_lseek,
556 .release = seq_release,
557};
558#endif
559
560extern struct seq_operations proc_pid_smaps_op;
561static int smaps_open(struct inode *inode, struct file *file)
562{
563 struct task_struct *task = proc_task(inode);
564 int ret = seq_open(file, &proc_pid_smaps_op);
565 if (!ret) {
566 struct seq_file *m = file->private_data;
567 m->private = task;
568 }
569 return ret;
570}
571
572static struct file_operations proc_smaps_operations = {
573 .open = smaps_open,
574 .read = seq_read,
575 .llseek = seq_lseek,
576 .release = seq_release,
577};
578
518extern struct seq_operations mounts_op; 579extern struct seq_operations mounts_op;
519static int mounts_open(struct inode *inode, struct file *file) 580static int mounts_open(struct inode *inode, struct file *file)
520{ 581{
@@ -597,7 +658,7 @@ static ssize_t mem_read(struct file * file, char __user * buf,
597 int ret = -ESRCH; 658 int ret = -ESRCH;
598 struct mm_struct *mm; 659 struct mm_struct *mm;
599 660
600 if (!MAY_PTRACE(task) || !may_ptrace_attach(task)) 661 if (!MAY_PTRACE(task) || !ptrace_may_attach(task))
601 goto out; 662 goto out;
602 663
603 ret = -ENOMEM; 664 ret = -ENOMEM;
@@ -623,7 +684,7 @@ static ssize_t mem_read(struct file * file, char __user * buf,
623 684
624 this_len = (count > PAGE_SIZE) ? PAGE_SIZE : count; 685 this_len = (count > PAGE_SIZE) ? PAGE_SIZE : count;
625 retval = access_process_vm(task, src, page, this_len, 0); 686 retval = access_process_vm(task, src, page, this_len, 0);
626 if (!retval || !MAY_PTRACE(task) || !may_ptrace_attach(task)) { 687 if (!retval || !MAY_PTRACE(task) || !ptrace_may_attach(task)) {
627 if (!ret) 688 if (!ret)
628 ret = -EIO; 689 ret = -EIO;
629 break; 690 break;
@@ -661,7 +722,7 @@ static ssize_t mem_write(struct file * file, const char * buf,
661 struct task_struct *task = proc_task(file->f_dentry->d_inode); 722 struct task_struct *task = proc_task(file->f_dentry->d_inode);
662 unsigned long dst = *ppos; 723 unsigned long dst = *ppos;
663 724
664 if (!MAY_PTRACE(task) || !may_ptrace_attach(task)) 725 if (!MAY_PTRACE(task) || !ptrace_may_attach(task))
665 return -ESRCH; 726 return -ESRCH;
666 727
667 page = (char *)__get_free_page(GFP_USER); 728 page = (char *)__get_free_page(GFP_USER);
@@ -1524,6 +1585,12 @@ static struct dentry *proc_pident_lookup(struct inode *dir,
1524 case PROC_TGID_MAPS: 1585 case PROC_TGID_MAPS:
1525 inode->i_fop = &proc_maps_operations; 1586 inode->i_fop = &proc_maps_operations;
1526 break; 1587 break;
1588#ifdef CONFIG_NUMA
1589 case PROC_TID_NUMA_MAPS:
1590 case PROC_TGID_NUMA_MAPS:
1591 inode->i_fop = &proc_numa_maps_operations;
1592 break;
1593#endif
1527 case PROC_TID_MEM: 1594 case PROC_TID_MEM:
1528 case PROC_TGID_MEM: 1595 case PROC_TGID_MEM:
1529 inode->i_op = &proc_mem_inode_operations; 1596 inode->i_op = &proc_mem_inode_operations;
@@ -1539,6 +1606,10 @@ static struct dentry *proc_pident_lookup(struct inode *dir,
1539 case PROC_TGID_MOUNTS: 1606 case PROC_TGID_MOUNTS:
1540 inode->i_fop = &proc_mounts_operations; 1607 inode->i_fop = &proc_mounts_operations;
1541 break; 1608 break;
1609 case PROC_TID_SMAPS:
1610 case PROC_TGID_SMAPS:
1611 inode->i_fop = &proc_smaps_operations;
1612 break;
1542#ifdef CONFIG_SECURITY 1613#ifdef CONFIG_SECURITY
1543 case PROC_TID_ATTR: 1614 case PROC_TID_ATTR:
1544 inode->i_nlink = 2; 1615 inode->i_nlink = 2;
diff --git a/fs/proc/generic.c b/fs/proc/generic.c
index abe8920313fb..8a8c34461d48 100644
--- a/fs/proc/generic.c
+++ b/fs/proc/generic.c
@@ -249,6 +249,18 @@ out:
249 return error; 249 return error;
250} 250}
251 251
252static int proc_getattr(struct vfsmount *mnt, struct dentry *dentry,
253 struct kstat *stat)
254{
255 struct inode *inode = dentry->d_inode;
256 struct proc_dir_entry *de = PROC_I(inode)->pde;
257 if (de && de->nlink)
258 inode->i_nlink = de->nlink;
259
260 generic_fillattr(inode, stat);
261 return 0;
262}
263
252static struct inode_operations proc_file_inode_operations = { 264static struct inode_operations proc_file_inode_operations = {
253 .setattr = proc_notify_change, 265 .setattr = proc_notify_change,
254}; 266};
@@ -475,6 +487,7 @@ static struct file_operations proc_dir_operations = {
475 */ 487 */
476static struct inode_operations proc_dir_inode_operations = { 488static struct inode_operations proc_dir_inode_operations = {
477 .lookup = proc_lookup, 489 .lookup = proc_lookup,
490 .getattr = proc_getattr,
478 .setattr = proc_notify_change, 491 .setattr = proc_notify_change,
479}; 492};
480 493
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 28b4a0253a92..c7ef3e48e35b 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -2,8 +2,13 @@
2#include <linux/hugetlb.h> 2#include <linux/hugetlb.h>
3#include <linux/mount.h> 3#include <linux/mount.h>
4#include <linux/seq_file.h> 4#include <linux/seq_file.h>
5#include <linux/highmem.h>
6#include <linux/pagemap.h>
7#include <linux/mempolicy.h>
8
5#include <asm/elf.h> 9#include <asm/elf.h>
6#include <asm/uaccess.h> 10#include <asm/uaccess.h>
11#include <asm/tlbflush.h>
7#include "internal.h" 12#include "internal.h"
8 13
9char *task_mem(struct mm_struct *mm, char *buffer) 14char *task_mem(struct mm_struct *mm, char *buffer)
@@ -87,49 +92,58 @@ static void pad_len_spaces(struct seq_file *m, int len)
87 seq_printf(m, "%*c", len, ' '); 92 seq_printf(m, "%*c", len, ' ');
88} 93}
89 94
90static int show_map(struct seq_file *m, void *v) 95struct mem_size_stats
96{
97 unsigned long resident;
98 unsigned long shared_clean;
99 unsigned long shared_dirty;
100 unsigned long private_clean;
101 unsigned long private_dirty;
102};
103
104static int show_map_internal(struct seq_file *m, void *v, struct mem_size_stats *mss)
91{ 105{
92 struct task_struct *task = m->private; 106 struct task_struct *task = m->private;
93 struct vm_area_struct *map = v; 107 struct vm_area_struct *vma = v;
94 struct mm_struct *mm = map->vm_mm; 108 struct mm_struct *mm = vma->vm_mm;
95 struct file *file = map->vm_file; 109 struct file *file = vma->vm_file;
96 int flags = map->vm_flags; 110 int flags = vma->vm_flags;
97 unsigned long ino = 0; 111 unsigned long ino = 0;
98 dev_t dev = 0; 112 dev_t dev = 0;
99 int len; 113 int len;
100 114
101 if (file) { 115 if (file) {
102 struct inode *inode = map->vm_file->f_dentry->d_inode; 116 struct inode *inode = vma->vm_file->f_dentry->d_inode;
103 dev = inode->i_sb->s_dev; 117 dev = inode->i_sb->s_dev;
104 ino = inode->i_ino; 118 ino = inode->i_ino;
105 } 119 }
106 120
107 seq_printf(m, "%08lx-%08lx %c%c%c%c %08lx %02x:%02x %lu %n", 121 seq_printf(m, "%08lx-%08lx %c%c%c%c %08lx %02x:%02x %lu %n",
108 map->vm_start, 122 vma->vm_start,
109 map->vm_end, 123 vma->vm_end,
110 flags & VM_READ ? 'r' : '-', 124 flags & VM_READ ? 'r' : '-',
111 flags & VM_WRITE ? 'w' : '-', 125 flags & VM_WRITE ? 'w' : '-',
112 flags & VM_EXEC ? 'x' : '-', 126 flags & VM_EXEC ? 'x' : '-',
113 flags & VM_MAYSHARE ? 's' : 'p', 127 flags & VM_MAYSHARE ? 's' : 'p',
114 map->vm_pgoff << PAGE_SHIFT, 128 vma->vm_pgoff << PAGE_SHIFT,
115 MAJOR(dev), MINOR(dev), ino, &len); 129 MAJOR(dev), MINOR(dev), ino, &len);
116 130
117 /* 131 /*
118 * Print the dentry name for named mappings, and a 132 * Print the dentry name for named mappings, and a
119 * special [heap] marker for the heap: 133 * special [heap] marker for the heap:
120 */ 134 */
121 if (map->vm_file) { 135 if (file) {
122 pad_len_spaces(m, len); 136 pad_len_spaces(m, len);
123 seq_path(m, file->f_vfsmnt, file->f_dentry, ""); 137 seq_path(m, file->f_vfsmnt, file->f_dentry, "\n");
124 } else { 138 } else {
125 if (mm) { 139 if (mm) {
126 if (map->vm_start <= mm->start_brk && 140 if (vma->vm_start <= mm->start_brk &&
127 map->vm_end >= mm->brk) { 141 vma->vm_end >= mm->brk) {
128 pad_len_spaces(m, len); 142 pad_len_spaces(m, len);
129 seq_puts(m, "[heap]"); 143 seq_puts(m, "[heap]");
130 } else { 144 } else {
131 if (map->vm_start <= mm->start_stack && 145 if (vma->vm_start <= mm->start_stack &&
132 map->vm_end >= mm->start_stack) { 146 vma->vm_end >= mm->start_stack) {
133 147
134 pad_len_spaces(m, len); 148 pad_len_spaces(m, len);
135 seq_puts(m, "[stack]"); 149 seq_puts(m, "[stack]");
@@ -141,24 +155,146 @@ static int show_map(struct seq_file *m, void *v)
141 } 155 }
142 } 156 }
143 seq_putc(m, '\n'); 157 seq_putc(m, '\n');
144 if (m->count < m->size) /* map is copied successfully */ 158
145 m->version = (map != get_gate_vma(task))? map->vm_start: 0; 159 if (mss)
160 seq_printf(m,
161 "Size: %8lu kB\n"
162 "Rss: %8lu kB\n"
163 "Shared_Clean: %8lu kB\n"
164 "Shared_Dirty: %8lu kB\n"
165 "Private_Clean: %8lu kB\n"
166 "Private_Dirty: %8lu kB\n",
167 (vma->vm_end - vma->vm_start) >> 10,
168 mss->resident >> 10,
169 mss->shared_clean >> 10,
170 mss->shared_dirty >> 10,
171 mss->private_clean >> 10,
172 mss->private_dirty >> 10);
173
174 if (m->count < m->size) /* vma is copied successfully */
175 m->version = (vma != get_gate_vma(task))? vma->vm_start: 0;
146 return 0; 176 return 0;
147} 177}
148 178
179static int show_map(struct seq_file *m, void *v)
180{
181 return show_map_internal(m, v, 0);
182}
183
184static void smaps_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
185 unsigned long addr, unsigned long end,
186 struct mem_size_stats *mss)
187{
188 pte_t *pte, ptent;
189 unsigned long pfn;
190 struct page *page;
191
192 pte = pte_offset_map(pmd, addr);
193 do {
194 ptent = *pte;
195 if (pte_none(ptent) || !pte_present(ptent))
196 continue;
197
198 mss->resident += PAGE_SIZE;
199 pfn = pte_pfn(ptent);
200 if (!pfn_valid(pfn))
201 continue;
202
203 page = pfn_to_page(pfn);
204 if (page_count(page) >= 2) {
205 if (pte_dirty(ptent))
206 mss->shared_dirty += PAGE_SIZE;
207 else
208 mss->shared_clean += PAGE_SIZE;
209 } else {
210 if (pte_dirty(ptent))
211 mss->private_dirty += PAGE_SIZE;
212 else
213 mss->private_clean += PAGE_SIZE;
214 }
215 } while (pte++, addr += PAGE_SIZE, addr != end);
216 pte_unmap(pte - 1);
217 cond_resched_lock(&vma->vm_mm->page_table_lock);
218}
219
220static inline void smaps_pmd_range(struct vm_area_struct *vma, pud_t *pud,
221 unsigned long addr, unsigned long end,
222 struct mem_size_stats *mss)
223{
224 pmd_t *pmd;
225 unsigned long next;
226
227 pmd = pmd_offset(pud, addr);
228 do {
229 next = pmd_addr_end(addr, end);
230 if (pmd_none_or_clear_bad(pmd))
231 continue;
232 smaps_pte_range(vma, pmd, addr, next, mss);
233 } while (pmd++, addr = next, addr != end);
234}
235
236static inline void smaps_pud_range(struct vm_area_struct *vma, pgd_t *pgd,
237 unsigned long addr, unsigned long end,
238 struct mem_size_stats *mss)
239{
240 pud_t *pud;
241 unsigned long next;
242
243 pud = pud_offset(pgd, addr);
244 do {
245 next = pud_addr_end(addr, end);
246 if (pud_none_or_clear_bad(pud))
247 continue;
248 smaps_pmd_range(vma, pud, addr, next, mss);
249 } while (pud++, addr = next, addr != end);
250}
251
252static inline void smaps_pgd_range(struct vm_area_struct *vma,
253 unsigned long addr, unsigned long end,
254 struct mem_size_stats *mss)
255{
256 pgd_t *pgd;
257 unsigned long next;
258
259 pgd = pgd_offset(vma->vm_mm, addr);
260 do {
261 next = pgd_addr_end(addr, end);
262 if (pgd_none_or_clear_bad(pgd))
263 continue;
264 smaps_pud_range(vma, pgd, addr, next, mss);
265 } while (pgd++, addr = next, addr != end);
266}
267
268static int show_smap(struct seq_file *m, void *v)
269{
270 struct vm_area_struct *vma = v;
271 struct mm_struct *mm = vma->vm_mm;
272 struct mem_size_stats mss;
273
274 memset(&mss, 0, sizeof mss);
275
276 if (mm) {
277 spin_lock(&mm->page_table_lock);
278 smaps_pgd_range(vma, vma->vm_start, vma->vm_end, &mss);
279 spin_unlock(&mm->page_table_lock);
280 }
281
282 return show_map_internal(m, v, &mss);
283}
284
149static void *m_start(struct seq_file *m, loff_t *pos) 285static void *m_start(struct seq_file *m, loff_t *pos)
150{ 286{
151 struct task_struct *task = m->private; 287 struct task_struct *task = m->private;
152 unsigned long last_addr = m->version; 288 unsigned long last_addr = m->version;
153 struct mm_struct *mm; 289 struct mm_struct *mm;
154 struct vm_area_struct *map, *tail_map; 290 struct vm_area_struct *vma, *tail_vma;
155 loff_t l = *pos; 291 loff_t l = *pos;
156 292
157 /* 293 /*
158 * We remember last_addr rather than next_addr to hit with 294 * We remember last_addr rather than next_addr to hit with
159 * mmap_cache most of the time. We have zero last_addr at 295 * mmap_cache most of the time. We have zero last_addr at
160 * the begining and also after lseek. We will have -1 last_addr 296 * the beginning and also after lseek. We will have -1 last_addr
161 * after the end of the maps. 297 * after the end of the vmas.
162 */ 298 */
163 299
164 if (last_addr == -1UL) 300 if (last_addr == -1UL)
@@ -168,47 +304,47 @@ static void *m_start(struct seq_file *m, loff_t *pos)
168 if (!mm) 304 if (!mm)
169 return NULL; 305 return NULL;
170 306
171 tail_map = get_gate_vma(task); 307 tail_vma = get_gate_vma(task);
172 down_read(&mm->mmap_sem); 308 down_read(&mm->mmap_sem);
173 309
174 /* Start with last addr hint */ 310 /* Start with last addr hint */
175 if (last_addr && (map = find_vma(mm, last_addr))) { 311 if (last_addr && (vma = find_vma(mm, last_addr))) {
176 map = map->vm_next; 312 vma = vma->vm_next;
177 goto out; 313 goto out;
178 } 314 }
179 315
180 /* 316 /*
181 * Check the map index is within the range and do 317 * Check the vma index is within the range and do
182 * sequential scan until m_index. 318 * sequential scan until m_index.
183 */ 319 */
184 map = NULL; 320 vma = NULL;
185 if ((unsigned long)l < mm->map_count) { 321 if ((unsigned long)l < mm->map_count) {
186 map = mm->mmap; 322 vma = mm->mmap;
187 while (l-- && map) 323 while (l-- && vma)
188 map = map->vm_next; 324 vma = vma->vm_next;
189 goto out; 325 goto out;
190 } 326 }
191 327
192 if (l != mm->map_count) 328 if (l != mm->map_count)
193 tail_map = NULL; /* After gate map */ 329 tail_vma = NULL; /* After gate vma */
194 330
195out: 331out:
196 if (map) 332 if (vma)
197 return map; 333 return vma;
198 334
199 /* End of maps has reached */ 335 /* End of vmas has been reached */
200 m->version = (tail_map != NULL)? 0: -1UL; 336 m->version = (tail_vma != NULL)? 0: -1UL;
201 up_read(&mm->mmap_sem); 337 up_read(&mm->mmap_sem);
202 mmput(mm); 338 mmput(mm);
203 return tail_map; 339 return tail_vma;
204} 340}
205 341
206static void m_stop(struct seq_file *m, void *v) 342static void m_stop(struct seq_file *m, void *v)
207{ 343{
208 struct task_struct *task = m->private; 344 struct task_struct *task = m->private;
209 struct vm_area_struct *map = v; 345 struct vm_area_struct *vma = v;
210 if (map && map != get_gate_vma(task)) { 346 if (vma && vma != get_gate_vma(task)) {
211 struct mm_struct *mm = map->vm_mm; 347 struct mm_struct *mm = vma->vm_mm;
212 up_read(&mm->mmap_sem); 348 up_read(&mm->mmap_sem);
213 mmput(mm); 349 mmput(mm);
214 } 350 }
@@ -217,14 +353,14 @@ static void m_stop(struct seq_file *m, void *v)
217static void *m_next(struct seq_file *m, void *v, loff_t *pos) 353static void *m_next(struct seq_file *m, void *v, loff_t *pos)
218{ 354{
219 struct task_struct *task = m->private; 355 struct task_struct *task = m->private;
220 struct vm_area_struct *map = v; 356 struct vm_area_struct *vma = v;
221 struct vm_area_struct *tail_map = get_gate_vma(task); 357 struct vm_area_struct *tail_vma = get_gate_vma(task);
222 358
223 (*pos)++; 359 (*pos)++;
224 if (map && (map != tail_map) && map->vm_next) 360 if (vma && (vma != tail_vma) && vma->vm_next)
225 return map->vm_next; 361 return vma->vm_next;
226 m_stop(m, v); 362 m_stop(m, v);
227 return (map != tail_map)? tail_map: NULL; 363 return (vma != tail_vma)? tail_vma: NULL;
228} 364}
229 365
230struct seq_operations proc_pid_maps_op = { 366struct seq_operations proc_pid_maps_op = {
@@ -233,3 +369,140 @@ struct seq_operations proc_pid_maps_op = {
233 .stop = m_stop, 369 .stop = m_stop,
234 .show = show_map 370 .show = show_map
235}; 371};
372
373struct seq_operations proc_pid_smaps_op = {
374 .start = m_start,
375 .next = m_next,
376 .stop = m_stop,
377 .show = show_smap
378};
379
380#ifdef CONFIG_NUMA
381
382struct numa_maps {
383 unsigned long pages;
384 unsigned long anon;
385 unsigned long mapped;
386 unsigned long mapcount_max;
387 unsigned long node[MAX_NUMNODES];
388};
389
390/*
391 * Calculate numa node maps for a vma
392 */
393static struct numa_maps *get_numa_maps(const struct vm_area_struct *vma)
394{
395 struct page *page;
396 unsigned long vaddr;
397 struct mm_struct *mm = vma->vm_mm;
398 int i;
399 struct numa_maps *md = kmalloc(sizeof(struct numa_maps), GFP_KERNEL);
400
401 if (!md)
402 return NULL;
403 md->pages = 0;
404 md->anon = 0;
405 md->mapped = 0;
406 md->mapcount_max = 0;
407 for_each_node(i)
408 md->node[i] =0;
409
410 spin_lock(&mm->page_table_lock);
411 for (vaddr = vma->vm_start; vaddr < vma->vm_end; vaddr += PAGE_SIZE) {
412 page = follow_page(mm, vaddr, 0);
413 if (page) {
414 int count = page_mapcount(page);
415
416 if (count)
417 md->mapped++;
418 if (count > md->mapcount_max)
419 md->mapcount_max = count;
420 md->pages++;
421 if (PageAnon(page))
422 md->anon++;
423 md->node[page_to_nid(page)]++;
424 }
425 }
426 spin_unlock(&mm->page_table_lock);
427 return md;
428}
429
430static int show_numa_map(struct seq_file *m, void *v)
431{
432 struct task_struct *task = m->private;
433 struct vm_area_struct *vma = v;
434 struct mempolicy *pol;
435 struct numa_maps *md;
436 struct zone **z;
437 int n;
438 int first;
439
440 if (!vma->vm_mm)
441 return 0;
442
443 md = get_numa_maps(vma);
444 if (!md)
445 return 0;
446
447 seq_printf(m, "%08lx", vma->vm_start);
448 pol = get_vma_policy(task, vma, vma->vm_start);
449 /* Print policy */
450 switch (pol->policy) {
451 case MPOL_PREFERRED:
452 seq_printf(m, " prefer=%d", pol->v.preferred_node);
453 break;
454 case MPOL_BIND:
455 seq_printf(m, " bind={");
456 first = 1;
457 for (z = pol->v.zonelist->zones; *z; z++) {
458
459 if (!first)
460 seq_putc(m, ',');
461 else
462 first = 0;
463 seq_printf(m, "%d/%s", (*z)->zone_pgdat->node_id,
464 (*z)->name);
465 }
466 seq_putc(m, '}');
467 break;
468 case MPOL_INTERLEAVE:
469 seq_printf(m, " interleave={");
470 first = 1;
471 for_each_node(n) {
472 if (test_bit(n, pol->v.nodes)) {
473 if (!first)
474 seq_putc(m,',');
475 else
476 first = 0;
477 seq_printf(m, "%d",n);
478 }
479 }
480 seq_putc(m, '}');
481 break;
482 default:
483 seq_printf(m," default");
484 break;
485 }
486 seq_printf(m, " MaxRef=%lu Pages=%lu Mapped=%lu",
487 md->mapcount_max, md->pages, md->mapped);
488 if (md->anon)
489 seq_printf(m," Anon=%lu",md->anon);
490
491 for_each_online_node(n) {
492 if (md->node[n])
493 seq_printf(m, " N%d=%lu", n, md->node[n]);
494 }
495 seq_putc(m, '\n');
496 kfree(md);
497 if (m->count < m->size) /* vma is copied successfully */
498 m->version = (vma != get_gate_vma(task)) ? vma->vm_start : 0;
499 return 0;
500}
501
502struct seq_operations proc_pid_numa_maps_op = {
503 .start = m_start,
504 .next = m_next,
505 .stop = m_stop,
506 .show = show_numa_map
507};
508#endif