Skip to content

Commit 874bff1

Browse files
jakub50akpm00
authored andcommitted
mm: refactor of vma_merge()
Patch series "Refactor of vma_merge and new merge call", v4. I am currently working on my master's thesis trying to increase number of merges of VMAs currently failing because of page offset incompatibility and difference in their anon_vmas. The following refactor and added merge call included in this series is just two smaller upgrades I created along the way. This patch (of 2): Refactor vma_merge() to make it shorter and more understandable. Main change is the elimination of code duplicity in the case of merge next check. This is done by first doing checks and caching the results before executing the merge itself. The variable 'area' is divided into 'mid' and 'res' as previously it was used for two purposes, as the middle VMA between prev and next and also as the result of the merge itself. Exit paths are also unified. Link: https://lkml.kernel.org/r/[email protected] Link: https://lkml.kernel.org/r/[email protected] Signed-off-by: Jakub Matěna <[email protected]> Reviewed-by: Vlastimil Babka <[email protected]> Cc: Michal Hocko <[email protected]> Cc: Mel Gorman <[email protected]> Cc: Matthew Wilcox <[email protected]> Cc: Liam Howlett <[email protected]> Cc: Hugh Dickins <[email protected]> Cc: "Kirill A . Shutemov" <[email protected]> Cc: Rik van Riel <[email protected]> Cc: Steven Rostedt <[email protected]> Cc: Peter Zijlstra (Intel) <[email protected]> Signed-off-by: Andrew Morton <[email protected]>
1 parent 7f38eda commit 874bff1

File tree

1 file changed

+37
-50
lines changed

1 file changed

+37
-50
lines changed

mm/mmap.c

Lines changed: 37 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1005,8 +1005,10 @@ struct vm_area_struct *vma_merge(struct mm_struct *mm,
10051005
struct anon_vma_name *anon_name)
10061006
{
10071007
pgoff_t pglen = (end - addr) >> PAGE_SHIFT;
1008-
struct vm_area_struct *area, *next;
1009-
int err;
1008+
struct vm_area_struct *mid, *next, *res;
1009+
int err = -1;
1010+
bool merge_prev = false;
1011+
bool merge_next = false;
10101012

10111013
/*
10121014
* We later require that vma->vm_flags == vm_flags,
@@ -1016,75 +1018,60 @@ struct vm_area_struct *vma_merge(struct mm_struct *mm,
10161018
return NULL;
10171019

10181020
next = find_vma(mm, prev ? prev->vm_end : 0);
1019-
area = next;
1020-
if (area && area->vm_end == end) /* cases 6, 7, 8 */
1021+
mid = next;
1022+
if (next && next->vm_end == end) /* cases 6, 7, 8 */
10211023
next = find_vma(mm, next->vm_end);
10221024

10231025
/* verify some invariant that must be enforced by the caller */
10241026
VM_WARN_ON(prev && addr <= prev->vm_start);
1025-
VM_WARN_ON(area && end > area->vm_end);
1027+
VM_WARN_ON(mid && end > mid->vm_end);
10261028
VM_WARN_ON(addr >= end);
10271029

1028-
/*
1029-
* Can it merge with the predecessor?
1030-
*/
1030+
/* Can we merge the predecessor? */
10311031
if (prev && prev->vm_end == addr &&
10321032
mpol_equal(vma_policy(prev), policy) &&
10331033
can_vma_merge_after(prev, vm_flags,
10341034
anon_vma, file, pgoff,
10351035
vm_userfaultfd_ctx, anon_name)) {
1036-
/*
1037-
* OK, it can. Can we now merge in the successor as well?
1038-
*/
1039-
if (next && end == next->vm_start &&
1040-
mpol_equal(policy, vma_policy(next)) &&
1041-
can_vma_merge_before(next, vm_flags,
1042-
anon_vma, file,
1043-
pgoff+pglen,
1044-
vm_userfaultfd_ctx, anon_name) &&
1045-
is_mergeable_anon_vma(prev->anon_vma,
1046-
next->anon_vma, NULL)) {
1047-
/* cases 1, 6 */
1048-
err = __vma_adjust(prev, prev->vm_start,
1049-
next->vm_end, prev->vm_pgoff, NULL,
1050-
prev);
1051-
} else /* cases 2, 5, 7 */
1052-
err = __vma_adjust(prev, prev->vm_start,
1053-
end, prev->vm_pgoff, NULL, prev);
1054-
if (err)
1055-
return NULL;
1056-
khugepaged_enter_vma(prev, vm_flags);
1057-
return prev;
1036+
merge_prev = true;
10581037
}
1059-
1060-
/*
1061-
* Can this new request be merged in front of next?
1062-
*/
1038+
/* Can we merge the successor? */
10631039
if (next && end == next->vm_start &&
10641040
mpol_equal(policy, vma_policy(next)) &&
10651041
can_vma_merge_before(next, vm_flags,
10661042
anon_vma, file, pgoff+pglen,
10671043
vm_userfaultfd_ctx, anon_name)) {
1044+
merge_next = true;
1045+
}
1046+
/* Can we merge both the predecessor and the successor? */
1047+
if (merge_prev && merge_next &&
1048+
is_mergeable_anon_vma(prev->anon_vma,
1049+
next->anon_vma, NULL)) { /* cases 1, 6 */
1050+
err = __vma_adjust(prev, prev->vm_start,
1051+
next->vm_end, prev->vm_pgoff, NULL,
1052+
prev);
1053+
res = prev;
1054+
} else if (merge_prev) { /* cases 2, 5, 7 */
1055+
err = __vma_adjust(prev, prev->vm_start,
1056+
end, prev->vm_pgoff, NULL, prev);
1057+
res = prev;
1058+
} else if (merge_next) {
10681059
if (prev && addr < prev->vm_end) /* case 4 */
10691060
err = __vma_adjust(prev, prev->vm_start,
1070-
addr, prev->vm_pgoff, NULL, next);
1071-
else { /* cases 3, 8 */
1072-
err = __vma_adjust(area, addr, next->vm_end,
1073-
next->vm_pgoff - pglen, NULL, next);
1074-
/*
1075-
* In case 3 area is already equal to next and
1076-
* this is a noop, but in case 8 "area" has
1077-
* been removed and next was expanded over it.
1078-
*/
1079-
area = next;
1080-
}
1081-
if (err)
1082-
return NULL;
1083-
khugepaged_enter_vma(area, vm_flags);
1084-
return area;
1061+
addr, prev->vm_pgoff, NULL, next);
1062+
else /* cases 3, 8 */
1063+
err = __vma_adjust(mid, addr, next->vm_end,
1064+
next->vm_pgoff - pglen, NULL, next);
1065+
res = next;
10851066
}
10861067

1087-
return NULL;
1068+
/*
1069+
* Cannot merge with predecessor or successor or error in __vma_adjust?
1070+
*/
1071+
if (err)
1072+
return NULL;
1073+
khugepaged_enter_vma(res, vm_flags);
1074+
return res;
10881075
}
10891076

10901077
/*

0 commit comments

Comments
 (0)