Commit 7c88db0cb589df980acfb2f73c3595a0653004ec
Committed by
Alexey Dobriyan
1 parent
2515ddc6db
Exists in
master
and in
7 other branches
proc: fix vma display mismatch between /proc/pid/{maps,smaps}
Commit 4752c369789250eafcd7813e11c8fb689235b0d2 aka "maps4: simplify interdependence of maps and smaps" broke /proc/pid/smaps, causing it to display some vmas twice and other vmas not at all. For example: grep .- /proc/1/smaps >/tmp/smaps; diff /proc/1/maps /tmp/smaps 1 25d24 2 < 7fd7e23aa000-7fd7e23ac000 rw-p 7fd7e23aa000 00:00 0 3 28a28 4 > ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall] The bug has something to do with setting m->version before all the seq_printf's have been performed. show_map was doing this correctly, but show_smap was doing this in the middle of its seq_printf sequence. This patch arranges things so that the setting of m->version in show_smap is also done at the end of its seq_printf sequence. Testing: in addition to the above grep test, for each process I summed up the 'Rss' fields of /proc/pid/smaps and compared that to the 'VmRSS' field of /proc/pid/status. All matched except for Xorg (which has a /dev/mem mapping which Rss accounts for but VmRSS does not). This result gives us some confidence that neither /proc/pid/maps nor /proc/pid/smaps are any longer skipping or double-counting vmas. Signed-off-by: Joe Korty <joe.korty@ccur.com> Cc: Matt Mackall <mpm@selenic.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
Showing 1 changed file with 16 additions and 9 deletions Side-by-side Diff
fs/proc/task_mmu.c
... | ... | @@ -198,11 +198,8 @@ |
198 | 198 | return ret; |
199 | 199 | } |
200 | 200 | |
201 | -static int show_map(struct seq_file *m, void *v) | |
201 | +static void show_map_vma(struct seq_file *m, struct vm_area_struct *vma) | |
202 | 202 | { |
203 | - struct proc_maps_private *priv = m->private; | |
204 | - struct task_struct *task = priv->task; | |
205 | - struct vm_area_struct *vma = v; | |
206 | 203 | struct mm_struct *mm = vma->vm_mm; |
207 | 204 | struct file *file = vma->vm_file; |
208 | 205 | int flags = vma->vm_flags; |
209 | 206 | |
... | ... | @@ -254,7 +251,16 @@ |
254 | 251 | } |
255 | 252 | } |
256 | 253 | seq_putc(m, '\n'); |
254 | +} | |
257 | 255 | |
256 | +static int show_map(struct seq_file *m, void *v) | |
257 | +{ | |
258 | + struct vm_area_struct *vma = v; | |
259 | + struct proc_maps_private *priv = m->private; | |
260 | + struct task_struct *task = priv->task; | |
261 | + | |
262 | + show_map_vma(m, vma); | |
263 | + | |
258 | 264 | if (m->count < m->size) /* vma is copied successfully */ |
259 | 265 | m->version = (vma != get_gate_vma(task))? vma->vm_start: 0; |
260 | 266 | return 0; |
261 | 267 | |
... | ... | @@ -364,9 +370,10 @@ |
364 | 370 | |
365 | 371 | static int show_smap(struct seq_file *m, void *v) |
366 | 372 | { |
373 | + struct proc_maps_private *priv = m->private; | |
374 | + struct task_struct *task = priv->task; | |
367 | 375 | struct vm_area_struct *vma = v; |
368 | 376 | struct mem_size_stats mss; |
369 | - int ret; | |
370 | 377 | struct mm_walk smaps_walk = { |
371 | 378 | .pmd_entry = smaps_pte_range, |
372 | 379 | .mm = vma->vm_mm, |
... | ... | @@ -378,9 +385,7 @@ |
378 | 385 | if (vma->vm_mm && !is_vm_hugetlb_page(vma)) |
379 | 386 | walk_page_range(vma->vm_start, vma->vm_end, &smaps_walk); |
380 | 387 | |
381 | - ret = show_map(m, v); | |
382 | - if (ret) | |
383 | - return ret; | |
388 | + show_map_vma(m, vma); | |
384 | 389 | |
385 | 390 | seq_printf(m, |
386 | 391 | "Size: %8lu kB\n" |
... | ... | @@ -402,7 +407,9 @@ |
402 | 407 | mss.referenced >> 10, |
403 | 408 | mss.swap >> 10); |
404 | 409 | |
405 | - return ret; | |
410 | + if (m->count < m->size) /* vma is copied successfully */ | |
411 | + m->version = (vma != get_gate_vma(task)) ? vma->vm_start : 0; | |
412 | + return 0; | |
406 | 413 | } |
407 | 414 | |
408 | 415 | static const struct seq_operations proc_pid_smaps_op = { |