Add comments with ASCII diagrams to describe what we're doing, avoid
dubious use of PHYS_PFN(), and use vma_start_pgoff().

The most complicated scenario represented here is vmg->__adjust_next_start
- when this is set, vmg->[start, end] actually indicate the range to be
retained, so take special care to describe this accurately.

No functional change intended.

Signed-off-by: Lorenzo Stoakes <[email protected]>
---
 mm/vma.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 47 insertions(+), 4 deletions(-)

diff --git a/mm/vma.c b/mm/vma.c
index 6296acecf3b7..1e99fe8aa6ef 100644
--- a/mm/vma.c
+++ b/mm/vma.c
@@ -704,11 +704,54 @@ static void vmg_adjust_set_range(struct vma_merge_struct 
*vmg)
        pgoff_t pgoff;
 
        if (vmg->__adjust_middle_start) {
-               adjust = vmg->middle;
-               pgoff = adjust->vm_pgoff + PHYS_PFN(vmg->end - 
adjust->vm_start);
+               /*
+                * vmg->start    vmg->end
+                * |             |
+                * v    merge    v
+                * <------------->
+                *         delta
+                *        <------>
+                * |------|----------------|
+                * | prev |    middle      |
+                * |------|----------------|
+                *        ^
+                *        |
+                *        middle->vm_start
+                */
+               struct vm_area_struct *middle = vmg->middle;
+               const unsigned long delta = vmg->end - middle->vm_start;
+
+               pgoff = vma_start_pgoff(middle) + (delta >> PAGE_SHIFT);
+               adjust = middle;
        } else if (vmg->__adjust_next_start) {
-               adjust = vmg->next;
-               pgoff = adjust->vm_pgoff - PHYS_PFN(adjust->vm_start - 
vmg->end);
+               /*
+                *                Originally:
+                *
+                *            vmg->start   vmg->end
+                *            |            |
+                *            v    merge   v
+                *            <------------>
+                *            .            .
+                * merge_existing_range() updates to:
+                *            .            .
+                * vmg->start vmg->end     .
+                * |          |            .
+                * v  retain  v            .
+                * <---------->            .
+                *             delta       .
+                *            <----->      .
+                * |----------------|------|
+                * |    middle      | next |
+                * |----------------|------|
+                *                  ^
+                *                  |
+                *                  next->vm_start
+                */
+               struct vm_area_struct *next = vmg->next;
+               const unsigned long delta = next->vm_start - vmg->end;
+
+               pgoff = vma_start_pgoff(next) - (delta >> PAGE_SHIFT);
+               adjust = next;
        } else {
                return;
        }
-- 
2.54.0


Reply via email to