summaryrefslogtreecommitdiff
path: root/include/linux
diff options
context:
space:
mode:
authorAndrew Morton <akpm@osdl.org>2004-03-07 22:42:37 -0800
committerLinus Torvalds <torvalds@ppc970.osdl.org>2004-03-07 22:42:37 -0800
commitbc3d0059577fa9c59b2188e649e2a109b3fdde95 (patch)
tree9968c9d3623501e71e097cde21173fda402a13f5 /include/linux
parentecad96d53e6056d1bc2c1badec28b4ac68503fe9 (diff)
[PATCH] vma corruption fix
From: Hugh Dickins <hugh@veritas.com> Fixes bugzilla #2219 fork's dup_mmap leaves child mm_rb as copied from parent mm while doing all the copy_page_ranges, and then calls build_mmap_rb without holding page_table_lock. try_to_unmap_one's find_vma (holding page_table_lock not mmap_sem) coming on another cpu may cause mm mayhem. It may leave the child's mmap_cache pointing to a vma of the parent mm. When the parent exits and the child faults, quite what happens rather depends on what junk then inhabits vm_page_prot, which gets set in the page table, with page_add_rmap adding the ptep, but junk pte likely to fail the tests for page_remove_rmap. Eventually the child exits, the page table is freed and try_to_unmap_one oopses on null ptep_to_mm (but in a kernel with rss limiting, usually page_referenced hits the null ptep_to_mm first). This took me days and days to unravel! Big thanks to Matthieu for reporting it with a good test case.
Diffstat (limited to 'include/linux')
-rw-r--r--include/linux/mm.h3
1 files changed, 2 insertions, 1 deletions
diff --git a/include/linux/mm.h b/include/linux/mm.h
index d9c541550efd..da8873610af3 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -530,7 +530,8 @@ extern void si_meminfo_node(struct sysinfo *val, int nid);
/* mmap.c */
extern void insert_vm_struct(struct mm_struct *, struct vm_area_struct *);
-extern void build_mmap_rb(struct mm_struct *);
+extern void __vma_link_rb(struct mm_struct *, struct vm_area_struct *,
+ struct rb_node **, struct rb_node *);
extern void exit_mmap(struct mm_struct *);
extern unsigned long get_unmapped_area(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);