Commit dbf8685c8e21404e3a8ed244bd0219d3c4b89101
Committed by
Linus Torvalds
1 parent
d00c7b9937
Exists in
master
and in
4 other branches
[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 |
fs/proc/internal.h
fs/proc/nommu.c
... | ... | @@ -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