Skip to content

Commit

Permalink
mm/mmap: Fix error path in do_vmi_align_munmap()
Browse files Browse the repository at this point in the history
The error unrolling was leaving the VMAs detached in many cases and
leaving the locked_vm statistic altered, and skipping the unrolling
entirely in the case of the vma tree write failing.

Fix the error path by re-attaching the detached VMAs and adding the
necessary goto for the failed vma tree write, and fix the locked_vm
statistic by only updating after the vma tree write succeeds.

Fixes: 763ecb0 ("mm: remove the vma linked list")
Reported-by: Vegard Nossum <[email protected]>
Signed-off-by: Liam R. Howlett <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
howlett authored and torvalds committed Jun 18, 2023
1 parent 1b29d27 commit 606c812
Showing 1 changed file with 17 additions and 20 deletions.
37 changes: 17 additions & 20 deletions mm/mmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -2318,21 +2318,6 @@ int split_vma(struct vma_iterator *vmi, struct vm_area_struct *vma,
return __split_vma(vmi, vma, addr, new_below);
}

static inline int munmap_sidetree(struct vm_area_struct *vma,
struct ma_state *mas_detach)
{
vma_start_write(vma);
mas_set_range(mas_detach, vma->vm_start, vma->vm_end - 1);
if (mas_store_gfp(mas_detach, vma, GFP_KERNEL))
return -ENOMEM;

vma_mark_detached(vma, true);
if (vma->vm_flags & VM_LOCKED)
vma->vm_mm->locked_vm -= vma_pages(vma);

return 0;
}

/*
* do_vmi_align_munmap() - munmap the aligned region from @start to @end.
* @vmi: The vma iterator
Expand All @@ -2354,6 +2339,7 @@ do_vmi_align_munmap(struct vma_iterator *vmi, struct vm_area_struct *vma,
struct maple_tree mt_detach;
int count = 0;
int error = -ENOMEM;
unsigned long locked_vm = 0;
MA_STATE(mas_detach, &mt_detach, 0, 0);
mt_init_flags(&mt_detach, vmi->mas.tree->ma_flags & MT_FLAGS_LOCK_MASK);
mt_set_external_lock(&mt_detach, &mm->mmap_lock);
Expand Down Expand Up @@ -2399,9 +2385,13 @@ do_vmi_align_munmap(struct vma_iterator *vmi, struct vm_area_struct *vma,
if (error)
goto end_split_failed;
}
error = munmap_sidetree(next, &mas_detach);
if (error)
goto munmap_sidetree_failed;
vma_start_write(next);
mas_set_range(&mas_detach, next->vm_start, next->vm_end - 1);
if (mas_store_gfp(&mas_detach, next, GFP_KERNEL))
goto munmap_gather_failed;
vma_mark_detached(next, true);
if (next->vm_flags & VM_LOCKED)
locked_vm += vma_pages(next);

count++;
#ifdef CONFIG_DEBUG_VM_MAPLE_TREE
Expand Down Expand Up @@ -2447,10 +2437,12 @@ do_vmi_align_munmap(struct vma_iterator *vmi, struct vm_area_struct *vma,
}
#endif
/* Point of no return */
error = -ENOMEM;
vma_iter_set(vmi, start);
if (vma_iter_clear_gfp(vmi, start, end, GFP_KERNEL))
return -ENOMEM;
goto clear_tree_failed;

mm->locked_vm -= locked_vm;
mm->map_count -= count;
/*
* Do not downgrade mmap_lock if we are next to VM_GROWSDOWN or
Expand Down Expand Up @@ -2480,9 +2472,14 @@ do_vmi_align_munmap(struct vma_iterator *vmi, struct vm_area_struct *vma,
validate_mm(mm);
return downgrade ? 1 : 0;

clear_tree_failed:
userfaultfd_error:
munmap_sidetree_failed:
munmap_gather_failed:
end_split_failed:
mas_set(&mas_detach, 0);
mas_for_each(&mas_detach, next, end)
vma_mark_detached(next, false);

__mt_destroy(&mt_detach);
start_split_failed:
map_count_exceeded:
Expand Down

0 comments on commit 606c812

Please sign in to comment.