From d13ba37a34cf71d69858586382a7034ec2519751 Mon Sep 17 00:00:00 2001 From: "Liam R. Howlett" Date: Thu, 5 May 2022 13:51:19 -0700 Subject: [PATCH] mm/mmap: Introduce sub_vma() and use it in __split_vma() 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 --- mm/mmap.c | 118 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 70 insertions(+), 48 deletions(-) diff --git a/mm/mmap.c b/mm/mmap.c index 2dc1de1cbd99..443c0a06656d 100644 --- 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); -- 2.50.1