On Sat, Aug 17, 2024 at 01:18:29AM GMT, Pedro Falcato wrote:
> We were doing an extra mmap tree traversal just to check if the entire
> range is modifiable. This can be done when we iterate through the VMAs
> instead.
>
> Signed-off-by: Pedro Falcato <pedro.falc...@gmail.com>
> ---
>  mm/mmap.c | 11 +----------
>  mm/vma.c  | 19 ++++++++++++-------
>  2 files changed, 13 insertions(+), 17 deletions(-)
>
> diff --git a/mm/mmap.c b/mm/mmap.c
> index 3af256bacef3..30ae4cb5cec9 100644
> --- a/mm/mmap.c
> +++ b/mm/mmap.c
> @@ -1740,16 +1740,7 @@ int do_vma_munmap(struct vma_iterator *vmi, struct 
> vm_area_struct *vma,
>               unsigned long start, unsigned long end, struct list_head *uf,
>               bool unlock)
>  {
> -     struct mm_struct *mm = vma->vm_mm;
> -
> -     /*
> -      * Check if memory is sealed, prevent unmapping a sealed VMA.
> -      * can_modify_mm assumes we have acquired the lock on MM.
> -      */
> -     if (unlikely(!can_modify_mm(mm, start, end)))
> -             return -EPERM;
> -
> -     return do_vmi_align_munmap(vmi, vma, mm, start, end, uf, unlock);
> +     return do_vmi_align_munmap(vmi, vma, vma->vm_mm, start, end, uf, 
> unlock);
>  }
>

Oh I like this. Want more mm/mmap.c stuff to look like this, abstracting
actual functionality to mm/vma.c...

>  /*
> diff --git a/mm/vma.c b/mm/vma.c
> index 84965f2cd580..5850f7c0949b 100644
> --- a/mm/vma.c
> +++ b/mm/vma.c
> @@ -712,6 +712,12 @@ do_vmi_align_munmap(struct vma_iterator *vmi, struct 
> vm_area_struct *vma,
>               if (end < vma->vm_end && mm->map_count >= sysctl_max_map_count)
>                       goto map_count_exceeded;
>
> +             /* Don't bother splitting the VMA if we can't unmap it anyway */
> +             if (!can_modify_vma(vma)) {
> +                     error = -EPERM;
> +                     goto start_split_failed;
> +             }
> +
>               error = __split_vma(vmi, vma, start, 1);
>               if (error)
>                       goto start_split_failed;
> @@ -723,6 +729,11 @@ do_vmi_align_munmap(struct vma_iterator *vmi, struct 
> vm_area_struct *vma,
>        */
>       next = vma;
>       do {
> +             if (!can_modify_vma(next)) {
> +                     error = -EPERM;
> +                     goto modify_vma_failed;
> +             }
> +
>               /* Does it split the end? */
>               if (next->vm_end > end) {
>                       error = __split_vma(vmi, next, end, 0);
> @@ -815,6 +826,7 @@ do_vmi_align_munmap(struct vma_iterator *vmi, struct 
> vm_area_struct *vma,
>       __mt_destroy(&mt_detach);
>       return 0;
>
> +modify_vma_failed:
>  clear_tree_failed:
>  userfaultfd_error:
>  munmap_gather_failed:
> @@ -860,13 +872,6 @@ int do_vmi_munmap(struct vma_iterator *vmi, struct 
> mm_struct *mm,
>       if (end == start)
>               return -EINVAL;
>
> -     /*
> -      * Check if memory is sealed, prevent unmapping a sealed VMA.
> -      * can_modify_mm assumes we have acquired the lock on MM.
> -      */
> -     if (unlikely(!can_modify_mm(mm, start, end)))
> -             return -EPERM;
> -

This means we will arch_unmap() first, before realising we can't unmap,
however there are a number of other error conditions that would cause a
similar outcome in do_vmi_align_munmap() so I don't think that's a problem.

>       /* Find the first overlapping VMA */
>       vma = vma_find(vmi, end);
>       if (!vma) {
>
> --
> 2.46.0
>

LGTM, Reviewed-by: Lorenzo Stoakes <lorenzo.stoa...@oracle.com>

Reply via email to