aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2006-09-27 04:50:19 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-09-27 11:26:14 -0400
commitdbf8685c8e21404e3a8ed244bd0219d3c4b89101 (patch)
tree716b83de856049b51abf9770840ea122b7ca3285
parentd00c7b993712e4bb16d0012b35b654e40159b327 (diff)
[PATCH] NOMMU: Implement /proc/pid/maps for NOMMU
Implement /proc/pid/maps for NOMMU by reading the vm_area_list attached to current->mm->context.vmlist. Signed-off-by: David Howells <dhowells@redhat.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--Documentation/nommu-mmap.txt3
-rw-r--r--fs/proc/internal.h1
-rw-r--r--fs/proc/nommu.c20
-rw-r--r--fs/proc/task_nommu.c74
-rw-r--r--include/linux/proc_fs.h2
5 files changed, 80 insertions, 20 deletions
diff --git a/Documentation/nommu-mmap.txt b/Documentation/nommu-mmap.txt
index b88ebe4d808c..83f4b083d57e 100644
--- a/Documentation/nommu-mmap.txt
+++ b/Documentation/nommu-mmap.txt
@@ -116,6 +116,9 @@ FURTHER NOTES ON NO-MMU MMAP
116 (*) A list of all the mappings on the system is visible through /proc/maps in 116 (*) A list of all the mappings on the system is visible through /proc/maps in
117 no-MMU mode. 117 no-MMU mode.
118 118
119 (*) A list of all the mappings in use by a process is visible through
120 /proc/<pid>/maps in no-MMU mode.
121
119 (*) Supplying MAP_FIXED or a requesting a particular mapping address will 122 (*) Supplying MAP_FIXED or a requesting a particular mapping address will
120 result in an error. 123 result in an error.
121 124
diff --git a/fs/proc/internal.h b/fs/proc/internal.h
index 146a434ba944..987c773dbb20 100644
--- a/fs/proc/internal.h
+++ b/fs/proc/internal.h
@@ -28,6 +28,7 @@ do { \
28 (vmi)->largest_chunk = 0; \ 28 (vmi)->largest_chunk = 0; \
29} while(0) 29} while(0)
30 30
31extern int nommu_vma_show(struct seq_file *, struct vm_area_struct *);
31#endif 32#endif
32 33
33extern void create_seq_entry(char *name, mode_t mode, const struct file_operations *f); 34extern void create_seq_entry(char *name, mode_t mode, const struct file_operations *f);
diff --git a/fs/proc/nommu.c b/fs/proc/nommu.c
index cff10ab1af63..d7dbdf9e0f49 100644
--- a/fs/proc/nommu.c
+++ b/fs/proc/nommu.c
@@ -33,19 +33,15 @@
33#include "internal.h" 33#include "internal.h"
34 34
35/* 35/*
36 * display a list of all the VMAs the kernel knows about 36 * display a single VMA to a sequenced file
37 * - nommu kernals have a single flat list
38 */ 37 */
39static int nommu_vma_list_show(struct seq_file *m, void *v) 38int nommu_vma_show(struct seq_file *m, struct vm_area_struct *vma)
40{ 39{
41 struct vm_area_struct *vma;
42 unsigned long ino = 0; 40 unsigned long ino = 0;
43 struct file *file; 41 struct file *file;
44 dev_t dev = 0; 42 dev_t dev = 0;
45 int flags, len; 43 int flags, len;
46 44
47 vma = rb_entry((struct rb_node *) v, struct vm_area_struct, vm_rb);
48
49 flags = vma->vm_flags; 45 flags = vma->vm_flags;
50 file = vma->vm_file; 46 file = vma->vm_file;
51 47
@@ -78,6 +74,18 @@ static int nommu_vma_list_show(struct seq_file *m, void *v)
78 return 0; 74 return 0;
79} 75}
80 76
77/*
78 * display a list of all the VMAs the kernel knows about
79 * - nommu kernals have a single flat list
80 */
81static int nommu_vma_list_show(struct seq_file *m, void *v)
82{
83 struct vm_area_struct *vma;
84
85 vma = rb_entry((struct rb_node *) v, struct vm_area_struct, vm_rb);
86 return nommu_vma_show(m, vma);
87}
88
81static void *nommu_vma_list_start(struct seq_file *m, loff_t *_pos) 89static void *nommu_vma_list_start(struct seq_file *m, loff_t *_pos)
82{ 90{
83 struct rb_node *_rb; 91 struct rb_node *_rb;
diff --git a/fs/proc/task_nommu.c b/fs/proc/task_nommu.c
index 4616ed50ffcd..091aa8e48e02 100644
--- a/fs/proc/task_nommu.c
+++ b/fs/proc/task_nommu.c
@@ -138,25 +138,63 @@ out:
138} 138}
139 139
140/* 140/*
141 * Albert D. Cahalan suggested to fake entries for the traditional 141 * display mapping lines for a particular process's /proc/pid/maps
142 * sections here. This might be worth investigating.
143 */ 142 */
144static int show_map(struct seq_file *m, void *v) 143static int show_map(struct seq_file *m, void *_vml)
145{ 144{
146 return 0; 145 struct vm_list_struct *vml = _vml;
146 return nommu_vma_show(m, vml->vma);
147} 147}
148
148static void *m_start(struct seq_file *m, loff_t *pos) 149static void *m_start(struct seq_file *m, loff_t *pos)
149{ 150{
151 struct proc_maps_private *priv = m->private;
152 struct vm_list_struct *vml;
153 struct mm_struct *mm;
154 loff_t n = *pos;
155
156 /* pin the task and mm whilst we play with them */
157 priv->task = get_pid_task(priv->pid, PIDTYPE_PID);
158 if (!priv->task)
159 return NULL;
160
161 mm = get_task_mm(priv->task);
162 if (!mm) {
163 put_task_struct(priv->task);
164 priv->task = NULL;
165 return NULL;
166 }
167
168 down_read(&mm->mmap_sem);
169
170 /* start from the Nth VMA */
171 for (vml = mm->context.vmlist; vml; vml = vml->next)
172 if (n-- == 0)
173 return vml;
150 return NULL; 174 return NULL;
151} 175}
152static void m_stop(struct seq_file *m, void *v) 176
177static void m_stop(struct seq_file *m, void *_vml)
153{ 178{
179 struct proc_maps_private *priv = m->private;
180
181 if (priv->task) {
182 struct mm_struct *mm = priv->task->mm;
183 up_read(&mm->mmap_sem);
184 mmput(mm);
185 put_task_struct(priv->task);
186 }
154} 187}
155static void *m_next(struct seq_file *m, void *v, loff_t *pos) 188
189static void *m_next(struct seq_file *m, void *_vml, loff_t *pos)
156{ 190{
157 return NULL; 191 struct vm_list_struct *vml = _vml;
192
193 (*pos)++;
194 return vml ? vml->next : NULL;
158} 195}
159static struct seq_operations proc_pid_maps_op = { 196
197static struct seq_operations proc_pid_maps_ops = {
160 .start = m_start, 198 .start = m_start,
161 .next = m_next, 199 .next = m_next,
162 .stop = m_stop, 200 .stop = m_stop,
@@ -165,11 +203,19 @@ static struct seq_operations proc_pid_maps_op = {
165 203
166static int maps_open(struct inode *inode, struct file *file) 204static int maps_open(struct inode *inode, struct file *file)
167{ 205{
168 int ret; 206 struct proc_maps_private *priv;
169 ret = seq_open(file, &proc_pid_maps_op); 207 int ret = -ENOMEM;
170 if (!ret) { 208
171 struct seq_file *m = file->private_data; 209 priv = kzalloc(sizeof(*priv), GFP_KERNEL);
172 m->private = NULL; 210 if (priv) {
211 priv->pid = proc_pid(inode);
212 ret = seq_open(file, &proc_pid_maps_ops);
213 if (!ret) {
214 struct seq_file *m = file->private_data;
215 m->private = priv;
216 } else {
217 kfree(priv);
218 }
173 } 219 }
174 return ret; 220 return ret;
175} 221}
@@ -178,6 +224,6 @@ struct file_operations proc_maps_operations = {
178 .open = maps_open, 224 .open = maps_open,
179 .read = seq_read, 225 .read = seq_read,
180 .llseek = seq_lseek, 226 .llseek = seq_lseek,
181 .release = seq_release, 227 .release = seq_release_private,
182}; 228};
183 229
diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
index 3435ca38dd14..57f70bc8b24b 100644
--- a/include/linux/proc_fs.h
+++ b/include/linux/proc_fs.h
@@ -268,7 +268,9 @@ static inline struct proc_dir_entry *PDE(const struct inode *inode)
268struct proc_maps_private { 268struct proc_maps_private {
269 struct pid *pid; 269 struct pid *pid;
270 struct task_struct *task; 270 struct task_struct *task;
271#ifdef CONFIG_MMU
271 struct vm_area_struct *tail_vma; 272 struct vm_area_struct *tail_vma;
273#endif
272}; 274};
273 275
274#endif /* _LINUX_PROC_FS_H */ 276#endif /* _LINUX_PROC_FS_H */