From 6f427815aea3f769a60723d1a16c9388712a31d3 Mon Sep 17 00:00:00 2001 From: "Liam R. Howlett" Date: Fri, 20 Nov 2020 14:27:16 -0500 Subject: [PATCH] mm/mmap: Fix vma_shorten() to correctly set vm_pgoff and vm_flags Signed-off-by: Liam R. Howlett --- mm/mmap.c | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/mm/mmap.c b/mm/mmap.c index 19b809d238ee..2ff7ab8a6f61 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -2662,7 +2662,6 @@ void vma_shorten(struct vm_area_struct *vma, unsigned long start, struct mm_struct *mm = vma->vm_mm; unsigned long old_start = vma->vm_start; unsigned long old_end = vma->vm_end; -// unsigned long old_pgoff = vma->vm_pgoff; struct vm_area_struct *next = vma->vm_next; struct address_space *mapping = NULL; struct rb_root_cached *root = NULL; @@ -2671,19 +2670,24 @@ void vma_shorten(struct vm_area_struct *vma, unsigned long start, vma_init(unmap, mm); - if (end != old_end) { // shortening the start, unmap the end of vma. - unmap->vm_start = end; - unmap->vm_end = old_end; - unmap->vm_next = vma->vm_next; - unmap->vm_prev = vma; - } else { + unmap->vm_pgoff = vma->vm_pgoff; + unmap->vm_flags = vma->vm_flags; + if (end == old_end) { + /* Changing the start of the VMA. */ unmap->vm_start = old_start; unmap->vm_end = start; unmap->vm_next = vma; unmap->vm_prev = vma->vm_prev; + } else { + /* unmap will contain the end section of the VMA to be removed */ + unmap->vm_start = end; + unmap->vm_end = old_end; + unmap->vm_next = vma->vm_next; + unmap->vm_prev = vma; + unmap->vm_pgoff += ((old_start - end) >> PAGE_SHIFT); } - vma_adjust_trans_huge(vma, vma->vm_start, end, 0); + vma_adjust_trans_huge(vma, start, end, 0); if (file) { mapping = file->f_mapping; @@ -2704,11 +2708,12 @@ void vma_shorten(struct vm_area_struct *vma, unsigned long start, vma_interval_tree_remove(vma, root); } - if (end == old_end) + if (end == old_end) { // Altering the vm_start. vma->vm_pgoff += (old_start - start) >> PAGE_SHIFT; - - vma->vm_end = end; - vma->vm_start = start; + vma->vm_start = start; + } else { + vma->vm_end = end; + } if (file) { vma_interval_tree_insert(vma, root); @@ -2769,7 +2774,8 @@ int __do_munmap(struct mm_struct *mm, unsigned long start, size_t len, if (start > vma->vm_start) { if (unlikely(vma->vm_end > end)) { - // adjust the same vma twice requires a split. + /* Essentially, this means there is a hole punched in + * this VMA, so a split is unavoidable. */ int error; /* * Make sure that map_count on return from munmap() will -- 2.50.1