diff options
Diffstat (limited to 'fs/proc')
-rw-r--r-- | fs/proc/array.c | 2 | ||||
-rw-r--r-- | fs/proc/base.c | 82 | ||||
-rw-r--r-- | fs/proc/generic.c | 2 | ||||
-rw-r--r-- | fs/proc/inode.c | 17 | ||||
-rw-r--r-- | fs/proc/nommu.c | 1 | ||||
-rw-r--r-- | fs/proc/proc_devtree.c | 57 | ||||
-rw-r--r-- | fs/proc/proc_misc.c | 8 | ||||
-rw-r--r-- | fs/proc/task_mmu.c | 60 |
8 files changed, 147 insertions, 82 deletions
diff --git a/fs/proc/array.c b/fs/proc/array.c index d84eecacbeaf..3e1239e4b303 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c | |||
@@ -438,7 +438,7 @@ static int do_task_stat(struct task_struct *task, char * buffer, int whole) | |||
438 | jiffies_to_clock_t(it_real_value), | 438 | jiffies_to_clock_t(it_real_value), |
439 | start_time, | 439 | start_time, |
440 | vsize, | 440 | vsize, |
441 | mm ? get_mm_counter(mm, rss) : 0, /* you might want to shift this left 3 */ | 441 | mm ? get_mm_rss(mm) : 0, |
442 | rsslim, | 442 | rsslim, |
443 | mm ? mm->start_code : 0, | 443 | mm ? mm->start_code : 0, |
444 | mm ? mm->end_code : 0, | 444 | mm ? mm->end_code : 0, |
diff --git a/fs/proc/base.c b/fs/proc/base.c index fb34f88a4a74..634355e16986 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
@@ -70,6 +70,7 @@ | |||
70 | #include <linux/seccomp.h> | 70 | #include <linux/seccomp.h> |
71 | #include <linux/cpuset.h> | 71 | #include <linux/cpuset.h> |
72 | #include <linux/audit.h> | 72 | #include <linux/audit.h> |
73 | #include <linux/poll.h> | ||
73 | #include "internal.h" | 74 | #include "internal.h" |
74 | 75 | ||
75 | /* | 76 | /* |
@@ -103,7 +104,9 @@ enum pid_directory_inos { | |||
103 | PROC_TGID_NUMA_MAPS, | 104 | PROC_TGID_NUMA_MAPS, |
104 | PROC_TGID_MOUNTS, | 105 | PROC_TGID_MOUNTS, |
105 | PROC_TGID_WCHAN, | 106 | PROC_TGID_WCHAN, |
107 | #ifdef CONFIG_MMU | ||
106 | PROC_TGID_SMAPS, | 108 | PROC_TGID_SMAPS, |
109 | #endif | ||
107 | #ifdef CONFIG_SCHEDSTATS | 110 | #ifdef CONFIG_SCHEDSTATS |
108 | PROC_TGID_SCHEDSTAT, | 111 | PROC_TGID_SCHEDSTAT, |
109 | #endif | 112 | #endif |
@@ -141,7 +144,9 @@ enum pid_directory_inos { | |||
141 | PROC_TID_NUMA_MAPS, | 144 | PROC_TID_NUMA_MAPS, |
142 | PROC_TID_MOUNTS, | 145 | PROC_TID_MOUNTS, |
143 | PROC_TID_WCHAN, | 146 | PROC_TID_WCHAN, |
147 | #ifdef CONFIG_MMU | ||
144 | PROC_TID_SMAPS, | 148 | PROC_TID_SMAPS, |
149 | #endif | ||
145 | #ifdef CONFIG_SCHEDSTATS | 150 | #ifdef CONFIG_SCHEDSTATS |
146 | PROC_TID_SCHEDSTAT, | 151 | PROC_TID_SCHEDSTAT, |
147 | #endif | 152 | #endif |
@@ -195,7 +200,9 @@ static struct pid_entry tgid_base_stuff[] = { | |||
195 | E(PROC_TGID_ROOT, "root", S_IFLNK|S_IRWXUGO), | 200 | E(PROC_TGID_ROOT, "root", S_IFLNK|S_IRWXUGO), |
196 | E(PROC_TGID_EXE, "exe", S_IFLNK|S_IRWXUGO), | 201 | E(PROC_TGID_EXE, "exe", S_IFLNK|S_IRWXUGO), |
197 | E(PROC_TGID_MOUNTS, "mounts", S_IFREG|S_IRUGO), | 202 | E(PROC_TGID_MOUNTS, "mounts", S_IFREG|S_IRUGO), |
203 | #ifdef CONFIG_MMU | ||
198 | E(PROC_TGID_SMAPS, "smaps", S_IFREG|S_IRUGO), | 204 | E(PROC_TGID_SMAPS, "smaps", S_IFREG|S_IRUGO), |
205 | #endif | ||
199 | #ifdef CONFIG_SECURITY | 206 | #ifdef CONFIG_SECURITY |
200 | E(PROC_TGID_ATTR, "attr", S_IFDIR|S_IRUGO|S_IXUGO), | 207 | E(PROC_TGID_ATTR, "attr", S_IFDIR|S_IRUGO|S_IXUGO), |
201 | #endif | 208 | #endif |
@@ -235,7 +242,9 @@ static struct pid_entry tid_base_stuff[] = { | |||
235 | E(PROC_TID_ROOT, "root", S_IFLNK|S_IRWXUGO), | 242 | E(PROC_TID_ROOT, "root", S_IFLNK|S_IRWXUGO), |
236 | E(PROC_TID_EXE, "exe", S_IFLNK|S_IRWXUGO), | 243 | E(PROC_TID_EXE, "exe", S_IFLNK|S_IRWXUGO), |
237 | E(PROC_TID_MOUNTS, "mounts", S_IFREG|S_IRUGO), | 244 | E(PROC_TID_MOUNTS, "mounts", S_IFREG|S_IRUGO), |
245 | #ifdef CONFIG_MMU | ||
238 | E(PROC_TID_SMAPS, "smaps", S_IFREG|S_IRUGO), | 246 | E(PROC_TID_SMAPS, "smaps", S_IFREG|S_IRUGO), |
247 | #endif | ||
239 | #ifdef CONFIG_SECURITY | 248 | #ifdef CONFIG_SECURITY |
240 | E(PROC_TID_ATTR, "attr", S_IFDIR|S_IRUGO|S_IXUGO), | 249 | E(PROC_TID_ATTR, "attr", S_IFDIR|S_IRUGO|S_IXUGO), |
241 | #endif | 250 | #endif |
@@ -343,7 +352,8 @@ static int proc_root_link(struct inode *inode, struct dentry **dentry, struct vf | |||
343 | 352 | ||
344 | /* Same as proc_root_link, but this addionally tries to get fs from other | 353 | /* Same as proc_root_link, but this addionally tries to get fs from other |
345 | * threads in the group */ | 354 | * threads in the group */ |
346 | static int proc_task_root_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt) | 355 | static int proc_task_root_link(struct inode *inode, struct dentry **dentry, |
356 | struct vfsmount **mnt) | ||
347 | { | 357 | { |
348 | struct fs_struct *fs; | 358 | struct fs_struct *fs; |
349 | int result = -ENOENT; | 359 | int result = -ENOENT; |
@@ -357,9 +367,10 @@ static int proc_task_root_link(struct inode *inode, struct dentry **dentry, stru | |||
357 | } else { | 367 | } else { |
358 | /* Try to get fs from other threads */ | 368 | /* Try to get fs from other threads */ |
359 | task_unlock(leader); | 369 | task_unlock(leader); |
360 | struct task_struct *task = leader; | ||
361 | read_lock(&tasklist_lock); | 370 | read_lock(&tasklist_lock); |
362 | if (pid_alive(task)) { | 371 | if (pid_alive(leader)) { |
372 | struct task_struct *task = leader; | ||
373 | |||
363 | while ((task = next_thread(task)) != leader) { | 374 | while ((task = next_thread(task)) != leader) { |
364 | task_lock(task); | 375 | task_lock(task); |
365 | fs = task->fs; | 376 | fs = task->fs; |
@@ -628,6 +639,7 @@ static struct file_operations proc_numa_maps_operations = { | |||
628 | }; | 639 | }; |
629 | #endif | 640 | #endif |
630 | 641 | ||
642 | #ifdef CONFIG_MMU | ||
631 | extern struct seq_operations proc_pid_smaps_op; | 643 | extern struct seq_operations proc_pid_smaps_op; |
632 | static int smaps_open(struct inode *inode, struct file *file) | 644 | static int smaps_open(struct inode *inode, struct file *file) |
633 | { | 645 | { |
@@ -646,28 +658,41 @@ static struct file_operations proc_smaps_operations = { | |||
646 | .llseek = seq_lseek, | 658 | .llseek = seq_lseek, |
647 | .release = seq_release, | 659 | .release = seq_release, |
648 | }; | 660 | }; |
661 | #endif | ||
649 | 662 | ||
650 | extern struct seq_operations mounts_op; | 663 | extern struct seq_operations mounts_op; |
664 | struct proc_mounts { | ||
665 | struct seq_file m; | ||
666 | int event; | ||
667 | }; | ||
668 | |||
651 | static int mounts_open(struct inode *inode, struct file *file) | 669 | static int mounts_open(struct inode *inode, struct file *file) |
652 | { | 670 | { |
653 | struct task_struct *task = proc_task(inode); | 671 | struct task_struct *task = proc_task(inode); |
654 | int ret = seq_open(file, &mounts_op); | 672 | struct namespace *namespace; |
673 | struct proc_mounts *p; | ||
674 | int ret = -EINVAL; | ||
655 | 675 | ||
656 | if (!ret) { | 676 | task_lock(task); |
657 | struct seq_file *m = file->private_data; | 677 | namespace = task->namespace; |
658 | struct namespace *namespace; | 678 | if (namespace) |
659 | task_lock(task); | 679 | get_namespace(namespace); |
660 | namespace = task->namespace; | 680 | task_unlock(task); |
661 | if (namespace) | 681 | |
662 | get_namespace(namespace); | 682 | if (namespace) { |
663 | task_unlock(task); | 683 | ret = -ENOMEM; |
664 | 684 | p = kmalloc(sizeof(struct proc_mounts), GFP_KERNEL); | |
665 | if (namespace) | 685 | if (p) { |
666 | m->private = namespace; | 686 | file->private_data = &p->m; |
667 | else { | 687 | ret = seq_open(file, &mounts_op); |
668 | seq_release(inode, file); | 688 | if (!ret) { |
669 | ret = -EINVAL; | 689 | p->m.private = namespace; |
690 | p->event = namespace->event; | ||
691 | return 0; | ||
692 | } | ||
693 | kfree(p); | ||
670 | } | 694 | } |
695 | put_namespace(namespace); | ||
671 | } | 696 | } |
672 | return ret; | 697 | return ret; |
673 | } | 698 | } |
@@ -680,11 +705,30 @@ static int mounts_release(struct inode *inode, struct file *file) | |||
680 | return seq_release(inode, file); | 705 | return seq_release(inode, file); |
681 | } | 706 | } |
682 | 707 | ||
708 | static unsigned mounts_poll(struct file *file, poll_table *wait) | ||
709 | { | ||
710 | struct proc_mounts *p = file->private_data; | ||
711 | struct namespace *ns = p->m.private; | ||
712 | unsigned res = 0; | ||
713 | |||
714 | poll_wait(file, &ns->poll, wait); | ||
715 | |||
716 | spin_lock(&vfsmount_lock); | ||
717 | if (p->event != ns->event) { | ||
718 | p->event = ns->event; | ||
719 | res = POLLERR; | ||
720 | } | ||
721 | spin_unlock(&vfsmount_lock); | ||
722 | |||
723 | return res; | ||
724 | } | ||
725 | |||
683 | static struct file_operations proc_mounts_operations = { | 726 | static struct file_operations proc_mounts_operations = { |
684 | .open = mounts_open, | 727 | .open = mounts_open, |
685 | .read = seq_read, | 728 | .read = seq_read, |
686 | .llseek = seq_lseek, | 729 | .llseek = seq_lseek, |
687 | .release = mounts_release, | 730 | .release = mounts_release, |
731 | .poll = mounts_poll, | ||
688 | }; | 732 | }; |
689 | 733 | ||
690 | #define PROC_BLOCK_SIZE (3*1024) /* 4K page size but our output routines use some slack for overruns */ | 734 | #define PROC_BLOCK_SIZE (3*1024) /* 4K page size but our output routines use some slack for overruns */ |
@@ -1679,10 +1723,12 @@ static struct dentry *proc_pident_lookup(struct inode *dir, | |||
1679 | case PROC_TGID_MOUNTS: | 1723 | case PROC_TGID_MOUNTS: |
1680 | inode->i_fop = &proc_mounts_operations; | 1724 | inode->i_fop = &proc_mounts_operations; |
1681 | break; | 1725 | break; |
1726 | #ifdef CONFIG_MMU | ||
1682 | case PROC_TID_SMAPS: | 1727 | case PROC_TID_SMAPS: |
1683 | case PROC_TGID_SMAPS: | 1728 | case PROC_TGID_SMAPS: |
1684 | inode->i_fop = &proc_smaps_operations; | 1729 | inode->i_fop = &proc_smaps_operations; |
1685 | break; | 1730 | break; |
1731 | #endif | ||
1686 | #ifdef CONFIG_SECURITY | 1732 | #ifdef CONFIG_SECURITY |
1687 | case PROC_TID_ATTR: | 1733 | case PROC_TID_ATTR: |
1688 | inode->i_nlink = 2; | 1734 | inode->i_nlink = 2; |
diff --git a/fs/proc/generic.c b/fs/proc/generic.c index 8a8c34461d48..b638fb500743 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c | |||
@@ -533,7 +533,7 @@ static void proc_kill_inodes(struct proc_dir_entry *de) | |||
533 | */ | 533 | */ |
534 | file_list_lock(); | 534 | file_list_lock(); |
535 | list_for_each(p, &sb->s_files) { | 535 | list_for_each(p, &sb->s_files) { |
536 | struct file * filp = list_entry(p, struct file, f_list); | 536 | struct file * filp = list_entry(p, struct file, f_u.fu_list); |
537 | struct dentry * dentry = filp->f_dentry; | 537 | struct dentry * dentry = filp->f_dentry; |
538 | struct inode * inode; | 538 | struct inode * inode; |
539 | struct file_operations *fops; | 539 | struct file_operations *fops; |
diff --git a/fs/proc/inode.c b/fs/proc/inode.c index effa6c0c467a..e6a818a93f3d 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c | |||
@@ -156,10 +156,13 @@ struct inode *proc_get_inode(struct super_block *sb, unsigned int ino, | |||
156 | 156 | ||
157 | WARN_ON(de && de->deleted); | 157 | WARN_ON(de && de->deleted); |
158 | 158 | ||
159 | if (de != NULL && !try_module_get(de->owner)) | ||
160 | goto out_mod; | ||
161 | |||
159 | inode = iget(sb, ino); | 162 | inode = iget(sb, ino); |
160 | if (!inode) | 163 | if (!inode) |
161 | goto out_fail; | 164 | goto out_ino; |
162 | 165 | ||
163 | PROC_I(inode)->pde = de; | 166 | PROC_I(inode)->pde = de; |
164 | if (de) { | 167 | if (de) { |
165 | if (de->mode) { | 168 | if (de->mode) { |
@@ -171,20 +174,20 @@ struct inode *proc_get_inode(struct super_block *sb, unsigned int ino, | |||
171 | inode->i_size = de->size; | 174 | inode->i_size = de->size; |
172 | if (de->nlink) | 175 | if (de->nlink) |
173 | inode->i_nlink = de->nlink; | 176 | inode->i_nlink = de->nlink; |
174 | if (!try_module_get(de->owner)) | ||
175 | goto out_fail; | ||
176 | if (de->proc_iops) | 177 | if (de->proc_iops) |
177 | inode->i_op = de->proc_iops; | 178 | inode->i_op = de->proc_iops; |
178 | if (de->proc_fops) | 179 | if (de->proc_fops) |
179 | inode->i_fop = de->proc_fops; | 180 | inode->i_fop = de->proc_fops; |
180 | } | 181 | } |
181 | 182 | ||
182 | out: | ||
183 | return inode; | 183 | return inode; |
184 | 184 | ||
185 | out_fail: | 185 | out_ino: |
186 | if (de != NULL) | ||
187 | module_put(de->owner); | ||
188 | out_mod: | ||
186 | de_put(de); | 189 | de_put(de); |
187 | goto out; | 190 | return NULL; |
188 | } | 191 | } |
189 | 192 | ||
190 | int proc_fill_super(struct super_block *s, void *data, int silent) | 193 | int proc_fill_super(struct super_block *s, void *data, int silent) |
diff --git a/fs/proc/nommu.c b/fs/proc/nommu.c index f3bf016d5ee3..cff10ab1af63 100644 --- a/fs/proc/nommu.c +++ b/fs/proc/nommu.c | |||
@@ -91,6 +91,7 @@ static void *nommu_vma_list_start(struct seq_file *m, loff_t *_pos) | |||
91 | next = _rb; | 91 | next = _rb; |
92 | break; | 92 | break; |
93 | } | 93 | } |
94 | pos--; | ||
94 | } | 95 | } |
95 | 96 | ||
96 | return next; | 97 | return next; |
diff --git a/fs/proc/proc_devtree.c b/fs/proc/proc_devtree.c index 6fd57f154197..fb117b74809e 100644 --- a/fs/proc/proc_devtree.c +++ b/fs/proc/proc_devtree.c | |||
@@ -49,6 +49,39 @@ static int property_read_proc(char *page, char **start, off_t off, | |||
49 | */ | 49 | */ |
50 | 50 | ||
51 | /* | 51 | /* |
52 | * Add a property to a node | ||
53 | */ | ||
54 | static struct proc_dir_entry * | ||
55 | __proc_device_tree_add_prop(struct proc_dir_entry *de, struct property *pp) | ||
56 | { | ||
57 | struct proc_dir_entry *ent; | ||
58 | |||
59 | /* | ||
60 | * Unfortunately proc_register puts each new entry | ||
61 | * at the beginning of the list. So we rearrange them. | ||
62 | */ | ||
63 | ent = create_proc_read_entry(pp->name, | ||
64 | strncmp(pp->name, "security-", 9) | ||
65 | ? S_IRUGO : S_IRUSR, de, | ||
66 | property_read_proc, pp); | ||
67 | if (ent == NULL) | ||
68 | return NULL; | ||
69 | |||
70 | if (!strncmp(pp->name, "security-", 9)) | ||
71 | ent->size = 0; /* don't leak number of password chars */ | ||
72 | else | ||
73 | ent->size = pp->length; | ||
74 | |||
75 | return ent; | ||
76 | } | ||
77 | |||
78 | |||
79 | void proc_device_tree_add_prop(struct proc_dir_entry *pde, struct property *prop) | ||
80 | { | ||
81 | __proc_device_tree_add_prop(pde, prop); | ||
82 | } | ||
83 | |||
84 | /* | ||
52 | * Process a node, adding entries for its children and its properties. | 85 | * Process a node, adding entries for its children and its properties. |
53 | */ | 86 | */ |
54 | void proc_device_tree_add_node(struct device_node *np, | 87 | void proc_device_tree_add_node(struct device_node *np, |
@@ -57,11 +90,9 @@ void proc_device_tree_add_node(struct device_node *np, | |||
57 | struct property *pp; | 90 | struct property *pp; |
58 | struct proc_dir_entry *ent; | 91 | struct proc_dir_entry *ent; |
59 | struct device_node *child; | 92 | struct device_node *child; |
60 | struct proc_dir_entry *list = NULL, **lastp; | ||
61 | const char *p; | 93 | const char *p; |
62 | 94 | ||
63 | set_node_proc_entry(np, de); | 95 | set_node_proc_entry(np, de); |
64 | lastp = &list; | ||
65 | for (child = NULL; (child = of_get_next_child(np, child));) { | 96 | for (child = NULL; (child = of_get_next_child(np, child));) { |
66 | p = strrchr(child->full_name, '/'); | 97 | p = strrchr(child->full_name, '/'); |
67 | if (!p) | 98 | if (!p) |
@@ -71,9 +102,6 @@ void proc_device_tree_add_node(struct device_node *np, | |||
71 | ent = proc_mkdir(p, de); | 102 | ent = proc_mkdir(p, de); |
72 | if (ent == 0) | 103 | if (ent == 0) |
73 | break; | 104 | break; |
74 | *lastp = ent; | ||
75 | ent->next = NULL; | ||
76 | lastp = &ent->next; | ||
77 | proc_device_tree_add_node(child, ent); | 105 | proc_device_tree_add_node(child, ent); |
78 | } | 106 | } |
79 | of_node_put(child); | 107 | of_node_put(child); |
@@ -84,7 +112,7 @@ void proc_device_tree_add_node(struct device_node *np, | |||
84 | * properties are quite unimportant for us though, thus we | 112 | * properties are quite unimportant for us though, thus we |
85 | * simply "skip" them here, but we do have to check. | 113 | * simply "skip" them here, but we do have to check. |
86 | */ | 114 | */ |
87 | for (ent = list; ent != NULL; ent = ent->next) | 115 | for (ent = de->subdir; ent != NULL; ent = ent->next) |
88 | if (!strcmp(ent->name, pp->name)) | 116 | if (!strcmp(ent->name, pp->name)) |
89 | break; | 117 | break; |
90 | if (ent != NULL) { | 118 | if (ent != NULL) { |
@@ -94,25 +122,10 @@ void proc_device_tree_add_node(struct device_node *np, | |||
94 | continue; | 122 | continue; |
95 | } | 123 | } |
96 | 124 | ||
97 | /* | 125 | ent = __proc_device_tree_add_prop(de, pp); |
98 | * Unfortunately proc_register puts each new entry | ||
99 | * at the beginning of the list. So we rearrange them. | ||
100 | */ | ||
101 | ent = create_proc_read_entry(pp->name, | ||
102 | strncmp(pp->name, "security-", 9) | ||
103 | ? S_IRUGO : S_IRUSR, de, | ||
104 | property_read_proc, pp); | ||
105 | if (ent == 0) | 126 | if (ent == 0) |
106 | break; | 127 | break; |
107 | if (!strncmp(pp->name, "security-", 9)) | ||
108 | ent->size = 0; /* don't leak number of password chars */ | ||
109 | else | ||
110 | ent->size = pp->length; | ||
111 | ent->next = NULL; | ||
112 | *lastp = ent; | ||
113 | lastp = &ent->next; | ||
114 | } | 128 | } |
115 | de->subdir = list; | ||
116 | } | 129 | } |
117 | 130 | ||
118 | /* | 131 | /* |
diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c index a3453555a94e..5b6b0b6038a7 100644 --- a/fs/proc/proc_misc.c +++ b/fs/proc/proc_misc.c | |||
@@ -629,12 +629,4 @@ void __init proc_misc_init(void) | |||
629 | if (entry) | 629 | if (entry) |
630 | entry->proc_fops = &proc_sysrq_trigger_operations; | 630 | entry->proc_fops = &proc_sysrq_trigger_operations; |
631 | #endif | 631 | #endif |
632 | #ifdef CONFIG_PPC32 | ||
633 | { | ||
634 | extern struct file_operations ppc_htab_operations; | ||
635 | entry = create_proc_entry("ppc_htab", S_IRUGO|S_IWUSR, NULL); | ||
636 | if (entry) | ||
637 | entry->proc_fops = &ppc_htab_operations; | ||
638 | } | ||
639 | #endif | ||
640 | } | 632 | } |
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index c7ef3e48e35b..50bd5a8f0446 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c | |||
@@ -14,22 +14,41 @@ | |||
14 | char *task_mem(struct mm_struct *mm, char *buffer) | 14 | char *task_mem(struct mm_struct *mm, char *buffer) |
15 | { | 15 | { |
16 | unsigned long data, text, lib; | 16 | unsigned long data, text, lib; |
17 | unsigned long hiwater_vm, total_vm, hiwater_rss, total_rss; | ||
18 | |||
19 | /* | ||
20 | * Note: to minimize their overhead, mm maintains hiwater_vm and | ||
21 | * hiwater_rss only when about to *lower* total_vm or rss. Any | ||
22 | * collector of these hiwater stats must therefore get total_vm | ||
23 | * and rss too, which will usually be the higher. Barriers? not | ||
24 | * worth the effort, such snapshots can always be inconsistent. | ||
25 | */ | ||
26 | hiwater_vm = total_vm = mm->total_vm; | ||
27 | if (hiwater_vm < mm->hiwater_vm) | ||
28 | hiwater_vm = mm->hiwater_vm; | ||
29 | hiwater_rss = total_rss = get_mm_rss(mm); | ||
30 | if (hiwater_rss < mm->hiwater_rss) | ||
31 | hiwater_rss = mm->hiwater_rss; | ||
17 | 32 | ||
18 | data = mm->total_vm - mm->shared_vm - mm->stack_vm; | 33 | data = mm->total_vm - mm->shared_vm - mm->stack_vm; |
19 | text = (PAGE_ALIGN(mm->end_code) - (mm->start_code & PAGE_MASK)) >> 10; | 34 | text = (PAGE_ALIGN(mm->end_code) - (mm->start_code & PAGE_MASK)) >> 10; |
20 | lib = (mm->exec_vm << (PAGE_SHIFT-10)) - text; | 35 | lib = (mm->exec_vm << (PAGE_SHIFT-10)) - text; |
21 | buffer += sprintf(buffer, | 36 | buffer += sprintf(buffer, |
37 | "VmPeak:\t%8lu kB\n" | ||
22 | "VmSize:\t%8lu kB\n" | 38 | "VmSize:\t%8lu kB\n" |
23 | "VmLck:\t%8lu kB\n" | 39 | "VmLck:\t%8lu kB\n" |
40 | "VmHWM:\t%8lu kB\n" | ||
24 | "VmRSS:\t%8lu kB\n" | 41 | "VmRSS:\t%8lu kB\n" |
25 | "VmData:\t%8lu kB\n" | 42 | "VmData:\t%8lu kB\n" |
26 | "VmStk:\t%8lu kB\n" | 43 | "VmStk:\t%8lu kB\n" |
27 | "VmExe:\t%8lu kB\n" | 44 | "VmExe:\t%8lu kB\n" |
28 | "VmLib:\t%8lu kB\n" | 45 | "VmLib:\t%8lu kB\n" |
29 | "VmPTE:\t%8lu kB\n", | 46 | "VmPTE:\t%8lu kB\n", |
30 | (mm->total_vm - mm->reserved_vm) << (PAGE_SHIFT-10), | 47 | hiwater_vm << (PAGE_SHIFT-10), |
48 | (total_vm - mm->reserved_vm) << (PAGE_SHIFT-10), | ||
31 | mm->locked_vm << (PAGE_SHIFT-10), | 49 | mm->locked_vm << (PAGE_SHIFT-10), |
32 | get_mm_counter(mm, rss) << (PAGE_SHIFT-10), | 50 | hiwater_rss << (PAGE_SHIFT-10), |
51 | total_rss << (PAGE_SHIFT-10), | ||
33 | data << (PAGE_SHIFT-10), | 52 | data << (PAGE_SHIFT-10), |
34 | mm->stack_vm << (PAGE_SHIFT-10), text, lib, | 53 | mm->stack_vm << (PAGE_SHIFT-10), text, lib, |
35 | (PTRS_PER_PTE*sizeof(pte_t)*mm->nr_ptes) >> 10); | 54 | (PTRS_PER_PTE*sizeof(pte_t)*mm->nr_ptes) >> 10); |
@@ -44,13 +63,11 @@ unsigned long task_vsize(struct mm_struct *mm) | |||
44 | int task_statm(struct mm_struct *mm, int *shared, int *text, | 63 | int task_statm(struct mm_struct *mm, int *shared, int *text, |
45 | int *data, int *resident) | 64 | int *data, int *resident) |
46 | { | 65 | { |
47 | int rss = get_mm_counter(mm, rss); | 66 | *shared = get_mm_counter(mm, file_rss); |
48 | |||
49 | *shared = rss - get_mm_counter(mm, anon_rss); | ||
50 | *text = (PAGE_ALIGN(mm->end_code) - (mm->start_code & PAGE_MASK)) | 67 | *text = (PAGE_ALIGN(mm->end_code) - (mm->start_code & PAGE_MASK)) |
51 | >> PAGE_SHIFT; | 68 | >> PAGE_SHIFT; |
52 | *data = mm->total_vm - mm->shared_vm; | 69 | *data = mm->total_vm - mm->shared_vm; |
53 | *resident = rss; | 70 | *resident = *shared + get_mm_counter(mm, anon_rss); |
54 | return mm->total_vm; | 71 | return mm->total_vm; |
55 | } | 72 | } |
56 | 73 | ||
@@ -178,7 +195,7 @@ static int show_map_internal(struct seq_file *m, void *v, struct mem_size_stats | |||
178 | 195 | ||
179 | static int show_map(struct seq_file *m, void *v) | 196 | static int show_map(struct seq_file *m, void *v) |
180 | { | 197 | { |
181 | return show_map_internal(m, v, 0); | 198 | return show_map_internal(m, v, NULL); |
182 | } | 199 | } |
183 | 200 | ||
184 | static void smaps_pte_range(struct vm_area_struct *vma, pmd_t *pmd, | 201 | static void smaps_pte_range(struct vm_area_struct *vma, pmd_t *pmd, |
@@ -186,13 +203,14 @@ static void smaps_pte_range(struct vm_area_struct *vma, pmd_t *pmd, | |||
186 | struct mem_size_stats *mss) | 203 | struct mem_size_stats *mss) |
187 | { | 204 | { |
188 | pte_t *pte, ptent; | 205 | pte_t *pte, ptent; |
206 | spinlock_t *ptl; | ||
189 | unsigned long pfn; | 207 | unsigned long pfn; |
190 | struct page *page; | 208 | struct page *page; |
191 | 209 | ||
192 | pte = pte_offset_map(pmd, addr); | 210 | pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl); |
193 | do { | 211 | do { |
194 | ptent = *pte; | 212 | ptent = *pte; |
195 | if (pte_none(ptent) || !pte_present(ptent)) | 213 | if (!pte_present(ptent)) |
196 | continue; | 214 | continue; |
197 | 215 | ||
198 | mss->resident += PAGE_SIZE; | 216 | mss->resident += PAGE_SIZE; |
@@ -213,8 +231,8 @@ static void smaps_pte_range(struct vm_area_struct *vma, pmd_t *pmd, | |||
213 | mss->private_clean += PAGE_SIZE; | 231 | mss->private_clean += PAGE_SIZE; |
214 | } | 232 | } |
215 | } while (pte++, addr += PAGE_SIZE, addr != end); | 233 | } while (pte++, addr += PAGE_SIZE, addr != end); |
216 | pte_unmap(pte - 1); | 234 | pte_unmap_unlock(pte - 1, ptl); |
217 | cond_resched_lock(&vma->vm_mm->page_table_lock); | 235 | cond_resched(); |
218 | } | 236 | } |
219 | 237 | ||
220 | static inline void smaps_pmd_range(struct vm_area_struct *vma, pud_t *pud, | 238 | static inline void smaps_pmd_range(struct vm_area_struct *vma, pud_t *pud, |
@@ -268,17 +286,11 @@ static inline void smaps_pgd_range(struct vm_area_struct *vma, | |||
268 | static int show_smap(struct seq_file *m, void *v) | 286 | static int show_smap(struct seq_file *m, void *v) |
269 | { | 287 | { |
270 | struct vm_area_struct *vma = v; | 288 | struct vm_area_struct *vma = v; |
271 | struct mm_struct *mm = vma->vm_mm; | ||
272 | struct mem_size_stats mss; | 289 | struct mem_size_stats mss; |
273 | 290 | ||
274 | memset(&mss, 0, sizeof mss); | 291 | memset(&mss, 0, sizeof mss); |
275 | 292 | if (vma->vm_mm) | |
276 | if (mm) { | ||
277 | spin_lock(&mm->page_table_lock); | ||
278 | smaps_pgd_range(vma, vma->vm_start, vma->vm_end, &mss); | 293 | 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); | 294 | return show_map_internal(m, v, &mss); |
283 | } | 295 | } |
284 | 296 | ||
@@ -390,12 +402,11 @@ struct numa_maps { | |||
390 | /* | 402 | /* |
391 | * Calculate numa node maps for a vma | 403 | * Calculate numa node maps for a vma |
392 | */ | 404 | */ |
393 | static struct numa_maps *get_numa_maps(const struct vm_area_struct *vma) | 405 | static struct numa_maps *get_numa_maps(struct vm_area_struct *vma) |
394 | { | 406 | { |
407 | int i; | ||
395 | struct page *page; | 408 | struct page *page; |
396 | unsigned long vaddr; | 409 | 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); | 410 | struct numa_maps *md = kmalloc(sizeof(struct numa_maps), GFP_KERNEL); |
400 | 411 | ||
401 | if (!md) | 412 | if (!md) |
@@ -407,9 +418,8 @@ static struct numa_maps *get_numa_maps(const struct vm_area_struct *vma) | |||
407 | for_each_node(i) | 418 | for_each_node(i) |
408 | md->node[i] =0; | 419 | md->node[i] =0; |
409 | 420 | ||
410 | spin_lock(&mm->page_table_lock); | ||
411 | for (vaddr = vma->vm_start; vaddr < vma->vm_end; vaddr += PAGE_SIZE) { | 421 | for (vaddr = vma->vm_start; vaddr < vma->vm_end; vaddr += PAGE_SIZE) { |
412 | page = follow_page(mm, vaddr, 0); | 422 | page = follow_page(vma, vaddr, 0); |
413 | if (page) { | 423 | if (page) { |
414 | int count = page_mapcount(page); | 424 | int count = page_mapcount(page); |
415 | 425 | ||
@@ -422,8 +432,8 @@ static struct numa_maps *get_numa_maps(const struct vm_area_struct *vma) | |||
422 | md->anon++; | 432 | md->anon++; |
423 | md->node[page_to_nid(page)]++; | 433 | md->node[page_to_nid(page)]++; |
424 | } | 434 | } |
435 | cond_resched(); | ||
425 | } | 436 | } |
426 | spin_unlock(&mm->page_table_lock); | ||
427 | return md; | 437 | return md; |
428 | } | 438 | } |
429 | 439 | ||
@@ -469,7 +479,7 @@ static int show_numa_map(struct seq_file *m, void *v) | |||
469 | seq_printf(m, " interleave={"); | 479 | seq_printf(m, " interleave={"); |
470 | first = 1; | 480 | first = 1; |
471 | for_each_node(n) { | 481 | for_each_node(n) { |
472 | if (test_bit(n, pol->v.nodes)) { | 482 | if (node_isset(n, pol->v.nodes)) { |
473 | if (!first) | 483 | if (!first) |
474 | seq_putc(m,','); | 484 | seq_putc(m,','); |
475 | else | 485 | else |