"uffd_ctx %px\n"
                "anon_name %px\n"
                "state %x\n"
-               "just_expand %d __remove_middle %d __remove_next %d\n",
+               "just_expand %d\n"
+               "__adjust_middle_start %d __adjust_next_start %d\n"
+               "__remove_middle %d __remove_next %d\n",
                vmg, vmg->mm, vmg->pgoff,
                vmg->vmi, vmg->vmi ? vma_iter_addr(vmg->vmi) : 0,
                vmg->vmi ? vma_iter_end(vmg->vmi) : 0,
 #endif
                vmg->anon_name,
                (int)vmg->state,
-               vmg->just_expand, vmg->__remove_middle, vmg->__remove_next);
+               vmg->just_expand,
+               vmg->__adjust_middle_start, vmg->__adjust_next_start,
+               vmg->__remove_middle, vmg->__remove_next);
 
        if (vmg->mm) {
                pr_warn("vmg %px mm:\n", vmg);
 
  *
  * On success, returns the merged VMA. Otherwise returns NULL.
  */
-static struct vm_area_struct *commit_merge(struct vma_merge_struct *vmg,
-               long adj_start)
+static struct vm_area_struct *commit_merge(struct vma_merge_struct *vmg)
 {
-       struct vma_prepare vp;
        struct vm_area_struct *remove = NULL;
        struct vm_area_struct *remove2 = NULL;
+       struct vma_prepare vp;
        struct vm_area_struct *adjust = NULL;
+       long adj_start;
+       bool merge_target;
+
        /*
-        * In all cases but that of merge right, shrink next, we write
-        * vmg->target to the maple tree and return this as the merged VMA.
+        * If modifying an existing VMA and we don't remove vmg->middle, then we
+        * shrink the adjacent VMA.
         */
-       bool merge_target = adj_start >= 0;
+       if (vmg->__adjust_middle_start) {
+               adjust = vmg->middle;
+               /* The POSITIVE value by which we offset vmg->middle->vm_start. */
+               adj_start = vmg->end - vmg->middle->vm_start;
+               merge_target = true;
+       } else if (vmg->__adjust_next_start) {
+               adjust = vmg->next;
+               /* The NEGATIVE value by which we offset vmg->next->vm_start. */
+               adj_start = -(vmg->middle->vm_end - vmg->end);
+               /*
+                * In all cases but this - merge right, shrink next - we write
+                * vmg->target to the maple tree and return this as the merged VMA.
+                */
+               merge_target = false;
+       } else {
+               adjust = NULL;
+               adj_start = 0;
+               merge_target = true;
+       }
 
        if (vmg->__remove_middle)
                remove = vmg->middle;
        if (vmg->__remove_next)
                remove2 = vmg->next;
 
-       if (adj_start > 0)
-               adjust = vmg->middle;
-       else if (adj_start < 0)
-               adjust = vmg->next;
-
        init_multi_vma_prep(&vp, vmg->target, adjust, remove, remove2);
 
        VM_WARN_ON(vp.anon_vma && adjust && adjust->anon_vma &&
        bool left_side = middle && start == middle->vm_start;
        bool right_side = middle && end == middle->vm_end;
        int err = 0;
-       long adj_start = 0;
        bool merge_left, merge_right, merge_both;
 
        mmap_assert_write_locked(vmg->mm);
                vmg->start = prev->vm_start;
                vmg->pgoff = prev->vm_pgoff;
 
-               /*
-                * We both expand prev and shrink middle.
-                */
                if (!vmg->__remove_middle)
-                       adj_start = vmg->end - middle->vm_start;
+                       vmg->__adjust_middle_start = true;
 
                err = dup_anon_vma(prev, middle, &anon_dup);
        } else { /* merge_right */
                         * IMPORTANT: This is the ONLY case where the final
                         * merged VMA is NOT vmg->target, but rather vmg->next.
                         */
+                       vmg->__adjust_next_start = true;
                        vmg->target = middle;
                        vmg->start = middle->vm_start;
                        vmg->end = start;
                        vmg->pgoff = middle->vm_pgoff;
-
-                       adj_start = -(middle->vm_end - start);
                }
 
                err = dup_anon_vma(next, middle, &anon_dup);
        if (err)
                goto abort;
 
-       res = commit_merge(vmg, adj_start);
+       res = commit_merge(vmg);
        if (!res) {
                if (anon_dup)
                        unlink_anon_vmas(anon_dup);
        if (remove_next)
                vmg->__remove_next = true;
 
-       if (!commit_merge(vmg, 0))
+       if (!commit_merge(vmg))
                goto nomem;
 
        return 0;