aboutsummaryrefslogtreecommitdiffstats
path: root/mm/mmap.c
diff options
context:
space:
mode:
authorCyrill Gorcunov <gorcunov@gmail.com>2014-01-23 18:53:42 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2014-01-23 19:36:53 -0500
commit34228d473efe764d4db7c0536375f0c993e6e06a (patch)
tree8a1a113c3fe59cccfc5005392f2fc68d6f7e657f /mm/mmap.c
parent871beb8c313ab270242022d314e37db5044e2bab (diff)
mm: ignore VM_SOFTDIRTY on VMA merging
The VM_SOFTDIRTY bit affects vma merge routine: if two VMAs has all bits in vm_flags matched except dirty bit the kernel can't longer merge them and this forces the kernel to generate new VMAs instead. It finally may lead to the situation when userspace application reaches vm.max_map_count limit and get crashed in worse case | (gimp:11768): GLib-ERROR **: gmem.c:110: failed to allocate 4096 bytes | | (file-tiff-load:12038): LibGimpBase-WARNING **: file-tiff-load: gimp_wire_read(): error | xinit: connection to X server lost | | waiting for X server to shut down | /usr/lib64/gimp/2.0/plug-ins/file-tiff-load terminated: Hangup | /usr/lib64/gimp/2.0/plug-ins/script-fu terminated: Hangup | /usr/lib64/gimp/2.0/plug-ins/script-fu terminated: Hangup https://bugzilla.kernel.org/show_bug.cgi?id=67651 https://bugzilla.gnome.org/show_bug.cgi?id=719619#c0 Initial problem came from missed VM_SOFTDIRTY in do_brk() routine but even if we would set up VM_SOFTDIRTY here, there is still a way to prevent VMAs from merging: one can call | echo 4 > /proc/$PID/clear_refs and clear all VM_SOFTDIRTY over all VMAs presented in memory map, then new do_brk() will try to extend old VMA and finds that dirty bit doesn't match thus new VMA will be generated. As discussed with Pavel, the right approach should be to ignore VM_SOFTDIRTY bit when we're trying to merge VMAs and if merge successed we mark extended VMA with dirty bit where needed. Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org> Reported-by: Bastian Hougaard <gnome@rvzt.net> Reported-by: Mel Gorman <mgorman@suse.de> Cc: Pavel Emelyanov <xemul@parallels.com> Cc: <stable@vger.kernel.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.c12
1 files changed, 10 insertions, 2 deletions
diff --git a/mm/mmap.c b/mm/mmap.c
index 126d8b976bfd..20ff0c33274c 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -894,7 +894,15 @@ again: remove_next = 1 + (end > next->vm_end);
894static inline int is_mergeable_vma(struct vm_area_struct *vma, 894static inline int is_mergeable_vma(struct vm_area_struct *vma,
895 struct file *file, unsigned long vm_flags) 895 struct file *file, unsigned long vm_flags)
896{ 896{
897 if (vma->vm_flags ^ vm_flags) 897 /*
898 * VM_SOFTDIRTY should not prevent from VMA merging, if we
899 * match the flags but dirty bit -- the caller should mark
900 * merged VMA as dirty. If dirty bit won't be excluded from
901 * comparison, we increase pressue on the memory system forcing
902 * the kernel to generate new VMAs when old one could be
903 * extended instead.
904 */
905 if ((vma->vm_flags ^ vm_flags) & ~VM_SOFTDIRTY)
898 return 0; 906 return 0;
899 if (vma->vm_file != file) 907 if (vma->vm_file != file)
900 return 0; 908 return 0;
@@ -1083,7 +1091,7 @@ static int anon_vma_compatible(struct vm_area_struct *a, struct vm_area_struct *
1083 return a->vm_end == b->vm_start && 1091 return a->vm_end == b->vm_start &&
1084 mpol_equal(vma_policy(a), vma_policy(b)) && 1092 mpol_equal(vma_policy(a), vma_policy(b)) &&
1085 a->vm_file == b->vm_file && 1093 a->vm_file == b->vm_file &&
1086 !((a->vm_flags ^ b->vm_flags) & ~(VM_READ|VM_WRITE|VM_EXEC)) && 1094 !((a->vm_flags ^ b->vm_flags) & ~(VM_READ|VM_WRITE|VM_EXEC|VM_SOFTDIRTY)) &&
1087 b->vm_pgoff == a->vm_pgoff + ((b->vm_start - a->vm_start) >> PAGE_SHIFT); 1095 b->vm_pgoff == a->vm_pgoff + ((b->vm_start - a->vm_start) >> PAGE_SHIFT);
1088} 1096}
1089 1097