Commit dbf8685c8e21404e3a8ed244bd0219d3c4b89101

Authored by David Howells
Committed by Linus Torvalds
1 parent d00c7b9937

[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>

Showing 5 changed files with 80 additions and 20 deletions Side-by-side Diff

Documentation/nommu-mmap.txt
... ... @@ -116,6 +116,9 @@
116 116 (*) A list of all the mappings on the system is visible through /proc/maps in
117 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 122 (*) Supplying MAP_FIXED or a requesting a particular mapping address will
120 123 result in an error.
121 124  
... ... @@ -28,6 +28,7 @@
28 28 (vmi)->largest_chunk = 0; \
29 29 } while(0)
30 30  
  31 +extern int nommu_vma_show(struct seq_file *, struct vm_area_struct *);
31 32 #endif
32 33  
33 34 extern void create_seq_entry(char *name, mode_t mode, const struct file_operations *f);
... ... @@ -33,19 +33,15 @@
33 33 #include "internal.h"
34 34  
35 35 /*
36   - * display a list of all the VMAs the kernel knows about
37   - * - nommu kernals have a single flat list
  36 + * display a single VMA to a sequenced file
38 37 */
39   -static int nommu_vma_list_show(struct seq_file *m, void *v)
  38 +int nommu_vma_show(struct seq_file *m, struct vm_area_struct *vma)
40 39 {
41   - struct vm_area_struct *vma;
42 40 unsigned long ino = 0;
43 41 struct file *file;
44 42 dev_t dev = 0;
45 43 int flags, len;
46 44  
47   - vma = rb_entry((struct rb_node *) v, struct vm_area_struct, vm_rb);
48   -
49 45 flags = vma->vm_flags;
50 46 file = vma->vm_file;
51 47  
... ... @@ -76,6 +72,18 @@
76 72  
77 73 seq_putc(m, '\n');
78 74 return 0;
  75 +}
  76 +
  77 +/*
  78 + * display a list of all the VMAs the kernel knows about
  79 + * - nommu kernals have a single flat list
  80 + */
  81 +static 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);
79 87 }
80 88  
81 89 static void *nommu_vma_list_start(struct seq_file *m, loff_t *_pos)
fs/proc/task_nommu.c
... ... @@ -138,25 +138,63 @@
138 138 }
139 139  
140 140 /*
141   - * Albert D. Cahalan suggested to fake entries for the traditional
142   - * sections here. This might be worth investigating.
  141 + * display mapping lines for a particular process's /proc/pid/maps
143 142 */
144   -static int show_map(struct seq_file *m, void *v)
  143 +static 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 +
148 149 static 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 174 return NULL;
151 175 }
152   -static void m_stop(struct seq_file *m, void *v)
  176 +
  177 +static 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 }
155   -static void *m_next(struct seq_file *m, void *v, loff_t *pos)
  188 +
  189 +static 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 }
159   -static struct seq_operations proc_pid_maps_op = {
  196 +
  197 +static struct seq_operations proc_pid_maps_ops = {
160 198 .start = m_start,
161 199 .next = m_next,
162 200 .stop = m_stop,
... ... @@ -165,11 +203,19 @@
165 203  
166 204 static int maps_open(struct inode *inode, struct file *file)
167 205 {
168   - int ret;
169   - ret = seq_open(file, &proc_pid_maps_op);
170   - if (!ret) {
171   - struct seq_file *m = file->private_data;
172   - m->private = NULL;
  206 + struct proc_maps_private *priv;
  207 + int ret = -ENOMEM;
  208 +
  209 + priv = kzalloc(sizeof(*priv), GFP_KERNEL);
  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 220 return ret;
175 221 }
... ... @@ -178,6 +224,6 @@
178 224 .open = maps_open,
179 225 .read = seq_read,
180 226 .llseek = seq_lseek,
181   - .release = seq_release,
  227 + .release = seq_release_private,
182 228 };
include/linux/proc_fs.h
... ... @@ -268,7 +268,9 @@
268 268 struct proc_maps_private {
269 269 struct pid *pid;
270 270 struct task_struct *task;
  271 +#ifdef CONFIG_MMU
271 272 struct vm_area_struct *tail_vma;
  273 +#endif
272 274 };
273 275  
274 276 #endif /* _LINUX_PROC_FS_H */