aboutsummaryrefslogtreecommitdiffstats
path: root/mm/mmap.c
diff options
context:
space:
mode:
authorShaohua Li <shaohua.li@intel.com>2011-05-24 20:11:20 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2011-05-25 11:39:04 -0400
commit965f55dea0e331152fa53941a51e4e16f9f06fae (patch)
tree3cf8beb31bac7b325b62e8ef75618e0086a3c760 /mm/mmap.c
parent5f70b962ccc2f2e6259417cf3d1233dc9e16cf5e (diff)
mmap: avoid merging cloned VMAs
Avoid merging a VMA with another VMA which is cloned from the parent process. The cloned VMA shares the anon_vma lock with the parent process's VMA. If we do the merge, more vmas (even the new range is only for current process) use the perent process's anon_vma lock. This introduces scalability issues. find_mergeable_anon_vma() already considers this case. Signed-off-by: Shaohua Li <shaohua.li@intel.com> Cc: Rik van Riel <riel@redhat.com> Cc: Hugh Dickins <hughd@google.com> Cc: Andi Kleen <andi@firstfloor.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm/mmap.c')
-rw-r--r--mm/mmap.c18
1 files changed, 13 insertions, 5 deletions
diff --git a/mm/mmap.c b/mm/mmap.c
index 15b1fae57efe..4fb5464f7707 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -703,9 +703,17 @@ static inline int is_mergeable_vma(struct vm_area_struct *vma,
703} 703}
704 704
705static inline int is_mergeable_anon_vma(struct anon_vma *anon_vma1, 705static inline int is_mergeable_anon_vma(struct anon_vma *anon_vma1,
706 struct anon_vma *anon_vma2) 706 struct anon_vma *anon_vma2,
707 struct vm_area_struct *vma)
707{ 708{
708 return !anon_vma1 || !anon_vma2 || (anon_vma1 == anon_vma2); 709 /*
710 * The list_is_singular() test is to avoid merging VMA cloned from
711 * parents. This can improve scalability caused by anon_vma lock.
712 */
713 if ((!anon_vma1 || !anon_vma2) && (!vma ||
714 list_is_singular(&vma->anon_vma_chain)))
715 return 1;
716 return anon_vma1 == anon_vma2;
709} 717}
710 718
711/* 719/*
@@ -724,7 +732,7 @@ can_vma_merge_before(struct vm_area_struct *vma, unsigned long vm_flags,
724 struct anon_vma *anon_vma, struct file *file, pgoff_t vm_pgoff) 732 struct anon_vma *anon_vma, struct file *file, pgoff_t vm_pgoff)
725{ 733{
726 if (is_mergeable_vma(vma, file, vm_flags) && 734 if (is_mergeable_vma(vma, file, vm_flags) &&
727 is_mergeable_anon_vma(anon_vma, vma->anon_vma)) { 735 is_mergeable_anon_vma(anon_vma, vma->anon_vma, vma)) {
728 if (vma->vm_pgoff == vm_pgoff) 736 if (vma->vm_pgoff == vm_pgoff)
729 return 1; 737 return 1;
730 } 738 }
@@ -743,7 +751,7 @@ can_vma_merge_after(struct vm_area_struct *vma, unsigned long vm_flags,
743 struct anon_vma *anon_vma, struct file *file, pgoff_t vm_pgoff) 751 struct anon_vma *anon_vma, struct file *file, pgoff_t vm_pgoff)
744{ 752{
745 if (is_mergeable_vma(vma, file, vm_flags) && 753 if (is_mergeable_vma(vma, file, vm_flags) &&
746 is_mergeable_anon_vma(anon_vma, vma->anon_vma)) { 754 is_mergeable_anon_vma(anon_vma, vma->anon_vma, vma)) {
747 pgoff_t vm_pglen; 755 pgoff_t vm_pglen;
748 vm_pglen = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; 756 vm_pglen = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
749 if (vma->vm_pgoff + vm_pglen == vm_pgoff) 757 if (vma->vm_pgoff + vm_pglen == vm_pgoff)
@@ -821,7 +829,7 @@ struct vm_area_struct *vma_merge(struct mm_struct *mm,
821 can_vma_merge_before(next, vm_flags, 829 can_vma_merge_before(next, vm_flags,
822 anon_vma, file, pgoff+pglen) && 830 anon_vma, file, pgoff+pglen) &&
823 is_mergeable_anon_vma(prev->anon_vma, 831 is_mergeable_anon_vma(prev->anon_vma,
824 next->anon_vma)) { 832 next->anon_vma, NULL)) {
825 /* cases 1, 6 */ 833 /* cases 1, 6 */
826 err = vma_adjust(prev, prev->vm_start, 834 err = vma_adjust(prev, prev->vm_start,
827 next->vm_end, prev->vm_pgoff, NULL); 835 next->vm_end, prev->vm_pgoff, NULL);