Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

mm/vma: use vmg->target to specify target VMA for new VMA merge

In commit 3a75ccba047b ("mm: simplify vma merge structure and expand
comments") we introduced the vmg->target field to make the merging of
existing VMAs simpler - clarifying precisely which VMA would eventually
become the merged VMA once the merge operation was complete.

New VMA merging did not get quite the same treatment, retaining the rather
confusing convention of storing the target VMA in vmg->middle.

This patch corrects this state of affairs, utilising vmg->target for this
purpose for both vma_merge_new_range() and also for vma_expand().

We retain the WARN_ON for vmg->middle being specified in
vma_merge_new_range() as doing so would make no sense, but add an
additional debug assert for setting vmg->target.

This patch additionally updates VMA userland testing to account for this
change.

[lorenzo.stoakes@oracle.com: make comment consistent in vma_expand()]
Link: https://lkml.kernel.org/r/c54f45e3-a6ac-4749-93c0-cc9e3080ee37@lucifer.local
Link: https://lkml.kernel.org/r/20250613184807.108089-1-lorenzo.stoakes@oracle.com
Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
Reviewed-by: Vlastimil Babka <vbabka@suse.cz>
Cc: Jann Horn <jannh@google.com>
Cc: Kees Cook <kees@kernel.org>
Cc: Liam Howlett <liam.howlett@oracle.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

authored by

Lorenzo Stoakes and committed by
Andrew Morton
4535cb33 9e82db9c

+23 -21
+19 -17
mm/vma.c
··· 1048 1048 1049 1049 mmap_assert_write_locked(vmg->mm); 1050 1050 VM_WARN_ON_VMG(vmg->middle, vmg); 1051 + VM_WARN_ON_VMG(vmg->target, vmg); 1051 1052 /* vmi must point at or before the gap. */ 1052 1053 VM_WARN_ON_VMG(vma_iter_addr(vmg->vmi) > end, vmg); 1053 1054 ··· 1064 1063 /* If we can merge with the next VMA, adjust vmg accordingly. */ 1065 1064 if (can_merge_right) { 1066 1065 vmg->end = next->vm_end; 1067 - vmg->middle = next; 1066 + vmg->target = next; 1068 1067 } 1069 1068 1070 1069 /* If we can merge with the previous VMA, adjust vmg accordingly. */ 1071 1070 if (can_merge_left) { 1072 1071 vmg->start = prev->vm_start; 1073 - vmg->middle = prev; 1072 + vmg->target = prev; 1074 1073 vmg->pgoff = prev->vm_pgoff; 1075 1074 1076 1075 /* ··· 1092 1091 * Now try to expand adjacent VMA(s). This takes care of removing the 1093 1092 * following VMA if we have VMAs on both sides. 1094 1093 */ 1095 - if (vmg->middle && !vma_expand(vmg)) { 1096 - khugepaged_enter_vma(vmg->middle, vmg->flags); 1094 + if (vmg->target && !vma_expand(vmg)) { 1095 + khugepaged_enter_vma(vmg->target, vmg->flags); 1097 1096 vmg->state = VMA_MERGE_SUCCESS; 1098 - return vmg->middle; 1097 + return vmg->target; 1099 1098 } 1100 1099 1101 1100 return NULL; ··· 1107 1106 * @vmg: Describes a VMA expansion operation. 1108 1107 * 1109 1108 * Expand @vma to vmg->start and vmg->end. Can expand off the start and end. 1110 - * Will expand over vmg->next if it's different from vmg->middle and vmg->end == 1111 - * vmg->next->vm_end. Checking if the vmg->middle can expand and merge with 1109 + * Will expand over vmg->next if it's different from vmg->target and vmg->end == 1110 + * vmg->next->vm_end. Checking if the vmg->target can expand and merge with 1112 1111 * vmg->next needs to be handled by the caller. 1113 1112 * 1114 1113 * Returns: 0 on success. 1115 1114 * 1116 1115 * ASSUMPTIONS: 1117 - * - The caller must hold a WRITE lock on vmg->middle->mm->mmap_lock. 1118 - * - The caller must have set @vmg->middle and @vmg->next. 1116 + * - The caller must hold a WRITE lock on the mm_struct->mmap_lock. 1117 + * - The caller must have set @vmg->target and @vmg->next. 1119 1118 */ 1120 1119 int vma_expand(struct vma_merge_struct *vmg) 1121 1120 { 1122 1121 struct vm_area_struct *anon_dup = NULL; 1123 1122 bool remove_next = false; 1124 - struct vm_area_struct *middle = vmg->middle; 1123 + struct vm_area_struct *target = vmg->target; 1125 1124 struct vm_area_struct *next = vmg->next; 1125 + 1126 + VM_WARN_ON_VMG(!target, vmg); 1126 1127 1127 1128 mmap_assert_write_locked(vmg->mm); 1128 1129 1129 - vma_start_write(middle); 1130 - if (next && (middle != next) && (vmg->end == next->vm_end)) { 1130 + vma_start_write(target); 1131 + if (next && (target != next) && (vmg->end == next->vm_end)) { 1131 1132 int ret; 1132 1133 1133 1134 remove_next = true; ··· 1140 1137 * In this case we don't report OOM, so vmg->give_up_on_mm is 1141 1138 * safe. 1142 1139 */ 1143 - ret = dup_anon_vma(middle, next, &anon_dup); 1140 + ret = dup_anon_vma(target, next, &anon_dup); 1144 1141 if (ret) 1145 1142 return ret; 1146 1143 } 1147 1144 1148 1145 /* Not merging but overwriting any part of next is not handled. */ 1149 1146 VM_WARN_ON_VMG(next && !remove_next && 1150 - next != middle && vmg->end > next->vm_start, vmg); 1147 + next != target && vmg->end > next->vm_start, vmg); 1151 1148 /* Only handles expanding */ 1152 - VM_WARN_ON_VMG(middle->vm_start < vmg->start || 1153 - middle->vm_end > vmg->end, vmg); 1149 + VM_WARN_ON_VMG(target->vm_start < vmg->start || 1150 + target->vm_end > vmg->end, vmg); 1154 1151 1155 - vmg->target = middle; 1156 1152 if (remove_next) 1157 1153 vmg->__remove_next = true; 1158 1154
+1 -1
mm/vma_exec.c
··· 54 54 /* 55 55 * cover the whole range: [new_start, old_end) 56 56 */ 57 - vmg.middle = vma; 57 + vmg.target = vma; 58 58 if (vma_expand(&vmg)) 59 59 return -ENOMEM; 60 60
+3 -3
tools/testing/vma/vma.c
··· 400 400 VMA_ITERATOR(vmi, &mm, 0); 401 401 struct vma_merge_struct vmg = { 402 402 .vmi = &vmi, 403 - .middle = vma, 403 + .target = vma, 404 404 .start = 0, 405 405 .end = 0x3000, 406 406 .pgoff = 0, ··· 1318 1318 vma_next->anon_vma = &dummy_anon_vma; 1319 1319 1320 1320 vmg_set_range(&vmg, 0, 0x5000, 0, flags); 1321 - vmg.middle = vma_prev; 1321 + vmg.target = vma_prev; 1322 1322 vmg.next = vma_next; 1323 1323 1324 1324 ASSERT_EQ(expand_existing(&vmg), 0); ··· 1501 1501 vma->anon_vma = &dummy_anon_vma; 1502 1502 1503 1503 vmg_set_range(&vmg, 0, 0x5000, 3, flags); 1504 - vmg.middle = vma_prev; 1504 + vmg.target = vma_prev; 1505 1505 vmg.next = vma; 1506 1506 1507 1507 fail_prealloc = true;