]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
mm/mmap: Introduce sub_vma() and use it in __split_vma()
authorLiam R. Howlett <Liam.Howlett@oracle.com>
Thu, 5 May 2022 20:51:19 +0000 (13:51 -0700)
committerLiam R. Howlett <Liam.Howlett@oracle.com>
Wed, 11 May 2022 14:46:53 +0000 (10:46 -0400)
sub_vma() creates a vma that covers a subset of the addresses covered by
the larger vma.  Use this new function in __split_vma() and in later
commits of the series.

Signed-off-by: Liam R. Howlett <Liam.Howlett@oracle.com>
mm/mmap.c

index 2dc1de1cbd99861287abd2624ecebed143e18203..443c0a06656dc151feadca335b01221465dec65b 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -2273,6 +2273,63 @@ static inline int vma_replace(struct vm_area_struct *vma,
        return 0;
 }
 
+/**
+ * sub_vma() - Create a vma that covers a part of another vma
+ * @mm: The mm_struct
+ * @vma: The large vma
+ * @new_vma: Pointer for the new vma
+ * @start: The start address
+ * @end: The end address
+ *
+ * Will clone the anon vma, take a ref to a file, call vm_ops open if needed.
+ * Returns: 0 on success
+ */
+int sub_vma(struct mm_struct *mm, struct vm_area_struct *vma,
+       struct vm_area_struct **new_vma, unsigned long start, unsigned long end)
+{
+       int err = -ENOMEM;
+
+       BUG_ON(vma->vm_start > end);
+       BUG_ON(vma->vm_end < start);
+       BUG_ON(start > end);
+
+       (*new_vma) = vm_area_dup(vma);
+       if (!(*new_vma))
+               return err;
+
+       if (start == vma->vm_start) {
+               (*new_vma)->vm_end = end;
+               (*new_vma)->vm_pgoff = vma->vm_pgoff;
+       } else {
+               (*new_vma)->vm_start = start;
+               (*new_vma)->vm_pgoff += ((start - vma->vm_start) >> PAGE_SHIFT);
+       }
+
+       err = vma_dup_policy(vma, *new_vma);
+       if (err)
+               goto no_new_vma_policy;
+
+       err = anon_vma_clone(*new_vma, vma);
+       if (err)
+               goto no_new_vma_anon;
+
+       if ((*new_vma)->vm_file) {
+               get_file((*new_vma)->vm_file);
+       }
+
+       if ((*new_vma)->vm_ops && (*new_vma)->vm_ops->open) {
+               (*new_vma)->vm_ops->open(*new_vma);
+       }
+
+       return 0;
+
+no_new_vma_anon:
+       mpol_put(vma_policy(*new_vma));
+no_new_vma_policy:
+       vm_area_free(*new_vma);
+       *new_vma = NULL;
+       return err;
+}
 /*
  * __split_vma() - Split one VMA into two new VMAs.
  * @mm: The mm_struct
@@ -2290,51 +2347,19 @@ int __split_vma(struct mm_struct *mm, struct vm_area_struct **vma,
        struct vm_area_struct *start, *end;
        int err;
        validate_mm_mt(mm);
-
        if ((*vma)->vm_ops && (*vma)->vm_ops->may_split) {
                err = (*vma)->vm_ops->may_split(*vma, addr);
                if (err)
                        return err;
        }
 
-       err = -ENOMEM;
-       start = vm_area_dup(*vma);
-       if (!start)
-               goto no_start;
-
-       end = vm_area_dup(*vma);
-       if (!end)
-               goto no_end;
-
-       start->vm_end = addr;
-       end->vm_start = addr;
-       end->vm_pgoff += ((addr - start->vm_start) >> PAGE_SHIFT);
-
-       err = vma_dup_policy(*vma, start);
+       err = sub_vma(mm, *vma, &start, (*vma)->vm_start, addr);
        if (err)
-               goto no_start_policy;
-
-       err = vma_dup_policy(*vma, end);
-       if (err)
-               goto no_end_policy;
-
-       err = anon_vma_clone(start, *vma);
-       if (err)
-               goto no_start_anon;
+               goto no_start;
 
-       err = anon_vma_clone(end, *vma);
+       err = sub_vma(mm, *vma, &end, addr, (*vma)->vm_end);
        if (err)
-               goto no_end_anon;
-
-       if (start->vm_file) {
-               get_file(start->vm_file);
-               get_file(end->vm_file);
-       }
-
-       if (start->vm_ops && start->vm_ops->open) {
-               start->vm_ops->open(start);
-               end->vm_ops->open(end);
-       }
+               goto no_end;
 
 
        if (vma_replace(*vma, start, end))
@@ -2348,24 +2373,21 @@ int __split_vma(struct mm_struct *mm, struct vm_area_struct **vma,
 
 no_replace:
        /* Clean everything up if vma_replace failed. */
-       if (start->vm_ops && start->vm_ops->close) {
-               start->vm_ops->close(start);
+       if (end->vm_ops && end->vm_ops->close)
                end->vm_ops->close(end);
-       }
-       if (start->vm_file) {
-               fput(start->vm_file);
+       if (end->vm_file)
                fput(end->vm_file);
-       }
        unlink_anon_vmas(end);
-no_end_anon:
-       unlink_anon_vmas(start);
-no_start_anon:
        mpol_put(vma_policy(end));
-no_end_policy:
-       mpol_put(vma_policy(start));
-no_start_policy:
        vm_area_free(end);
+
 no_end:
+       if (start->vm_ops && start->vm_ops->close)
+               start->vm_ops->close(start);
+       if (start->vm_file)
+               fput(start->vm_file);
+       unlink_anon_vmas(start);
+       mpol_put(vma_policy(start));
        vm_area_free(start);
 no_start:
        validate_mm_mt(mm);