[PATCH v4 11/21] mm/mmap: Reposition vma iterator in mmap_region()

From: Liam R. Howlett
Date: Wed Jul 10 2024 - 15:25:54 EST


From: "Liam R. Howlett" <Liam.Howlett@xxxxxxxxxx>

Instead of moving (or leaving) the vma iterator pointing at the previous
vma, leave it pointing at the insert location. Pointing the vma
iterator at the insert location allows for a cleaner walk of the vma
tree for MAP_FIXED and the no expansion cases.

The vma_prev() call in the case of merging the previous vma is
equivalent to vma_iter_prev_range(), since the vma iterator will be
pointing to the location just before the previous vma.

Signed-off-by: Liam R. Howlett <Liam.Howlett@xxxxxxxxxx>
Reviewed-by: Lorenzo Stoakes <lorenzo.stoakes@xxxxxxxxxx>
---
mm/mmap.c | 38 ++++++++++++++++++++++----------------
1 file changed, 22 insertions(+), 16 deletions(-)

diff --git a/mm/mmap.c b/mm/mmap.c
index e2e6b3202c25..83cfe575c114 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -2959,21 +2959,22 @@ unsigned long mmap_region(struct file *file, unsigned long addr,
mas_init(&mas_detach, &mt_detach, /* addr = */ 0);
/* Prepare to unmap any existing mapping in the area */
if (vms_gather_munmap_vmas(&vms, &mas_detach))
- return -ENOMEM;
+ goto gather_failed;

/* Remove any existing mappings from the vma tree */
if (vma_iter_clear_gfp(&vmi, addr, end, GFP_KERNEL))
- return -ENOMEM;
+ goto clear_tree_failed;

/* Unmap any existing mapping in the area */
vms_complete_munmap_vmas(&vms, &mas_detach);
next = vms.next;
prev = vms.prev;
- vma_prev(&vmi);
vma = NULL;
} else {
next = vma_next(&vmi);
prev = vma_prev(&vmi);
+ if (prev)
+ vma_iter_next_range(&vmi);
}

/*
@@ -2986,11 +2987,8 @@ unsigned long mmap_region(struct file *file, unsigned long addr,
vm_flags |= VM_ACCOUNT;
}

- if (vm_flags & VM_SPECIAL) {
- if (prev)
- vma_iter_next_range(&vmi);
+ if (vm_flags & VM_SPECIAL)
goto cannot_expand;
- }

/* Attempt to expand an old mapping */
/* Check next */
@@ -3011,19 +3009,21 @@ unsigned long mmap_region(struct file *file, unsigned long addr,
merge_start = prev->vm_start;
vma = prev;
vm_pgoff = prev->vm_pgoff;
- } else if (prev) {
- vma_iter_next_range(&vmi);
+ vma_prev(&vmi); /* Equivalent to going to the previous range */
}

- /* Actually expand, if possible */
- if (vma &&
- !vma_expand(&vmi, vma, merge_start, merge_end, vm_pgoff, next)) {
- khugepaged_enter_vma(vma, vm_flags);
- goto expanded;
+ if (vma) {
+ /* Actually expand, if possible */
+ if (!vma_expand(&vmi, vma, merge_start, merge_end, vm_pgoff, next)) {
+ khugepaged_enter_vma(vma, vm_flags);
+ goto expanded;
+ }
+
+ /* If the expand fails, then reposition the vma iterator */
+ if (unlikely(vma == prev))
+ vma_iter_set(&vmi, addr);
}

- if (vma == prev)
- vma_iter_set(&vmi, addr);
cannot_expand:

/*
@@ -3184,6 +3184,12 @@ unsigned long mmap_region(struct file *file, unsigned long addr,
vm_unacct_memory(charged);
validate_mm(mm);
return error;
+
+clear_tree_failed:
+ abort_munmap_vmas(&mas_detach);
+gather_failed:
+ validate_mm(mm);
+ return -ENOMEM;
}

static int __vm_munmap(unsigned long start, size_t len, bool unlock)
--
2.43.0