|
@@ -507,11 +507,12 @@ int vma_adjust(struct vm_area_struct *vma, unsigned long start,
|
|
|
struct address_space *mapping = NULL;
|
|
|
struct prio_tree_root *root = NULL;
|
|
|
struct file *file = vma->vm_file;
|
|
|
- struct anon_vma *anon_vma = NULL;
|
|
|
long adjust_next = 0;
|
|
|
int remove_next = 0;
|
|
|
|
|
|
if (next && !insert) {
|
|
|
+ struct vm_area_struct *exporter = NULL;
|
|
|
+
|
|
|
if (end >= next->vm_end) {
|
|
|
/*
|
|
|
* vma expands, overlapping all the next, and
|
|
@@ -519,7 +520,7 @@ int vma_adjust(struct vm_area_struct *vma, unsigned long start,
|
|
|
*/
|
|
|
again: remove_next = 1 + (end > next->vm_end);
|
|
|
end = next->vm_end;
|
|
|
- anon_vma = next->anon_vma;
|
|
|
+ exporter = next;
|
|
|
importer = vma;
|
|
|
} else if (end > next->vm_start) {
|
|
|
/*
|
|
@@ -527,7 +528,7 @@ again: remove_next = 1 + (end > next->vm_end);
|
|
|
* mprotect case 5 shifting the boundary up.
|
|
|
*/
|
|
|
adjust_next = (end - next->vm_start) >> PAGE_SHIFT;
|
|
|
- anon_vma = next->anon_vma;
|
|
|
+ exporter = next;
|
|
|
importer = vma;
|
|
|
} else if (end < vma->vm_end) {
|
|
|
/*
|
|
@@ -536,28 +537,19 @@ again: remove_next = 1 + (end > next->vm_end);
|
|
|
* mprotect case 4 shifting the boundary down.
|
|
|
*/
|
|
|
adjust_next = - ((vma->vm_end - end) >> PAGE_SHIFT);
|
|
|
- anon_vma = next->anon_vma;
|
|
|
+ exporter = vma;
|
|
|
importer = next;
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
- /*
|
|
|
- * When changing only vma->vm_end, we don't really need anon_vma lock.
|
|
|
- */
|
|
|
- if (vma->anon_vma && (insert || importer || start != vma->vm_start))
|
|
|
- anon_vma = vma->anon_vma;
|
|
|
- if (anon_vma) {
|
|
|
/*
|
|
|
* Easily overlooked: when mprotect shifts the boundary,
|
|
|
* make sure the expanding vma has anon_vma set if the
|
|
|
* shrinking vma had, to cover any anon pages imported.
|
|
|
*/
|
|
|
- if (importer && !importer->anon_vma) {
|
|
|
- /* Block reverse map lookups until things are set up. */
|
|
|
- if (anon_vma_clone(importer, vma)) {
|
|
|
+ if (exporter && exporter->anon_vma && !importer->anon_vma) {
|
|
|
+ if (anon_vma_clone(importer, exporter))
|
|
|
return -ENOMEM;
|
|
|
- }
|
|
|
- importer->anon_vma = anon_vma;
|
|
|
+ importer->anon_vma = exporter->anon_vma;
|
|
|
}
|
|
|
}
|
|
|
|