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
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))
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);