|
@@ -2069,6 +2069,18 @@ int expand_upwards(struct vm_area_struct *vma, unsigned long address)
|
|
|
if (vma->vm_pgoff + (size >> PAGE_SHIFT) >= vma->vm_pgoff) {
|
|
|
error = acct_stack_growth(vma, size, grow);
|
|
|
if (!error) {
|
|
|
+ /*
|
|
|
+ * vma_gap_update() doesn't support concurrent
|
|
|
+ * updates, but we only hold a shared mmap_sem
|
|
|
+ * lock here, so we need to protect against
|
|
|
+ * concurrent vma expansions.
|
|
|
+ * vma_lock_anon_vma() doesn't help here, as
|
|
|
+ * we don't guarantee that all growable vmas
|
|
|
+ * in a mm share the same root anon vma.
|
|
|
+ * So, we reuse mm->page_table_lock to guard
|
|
|
+ * against concurrent vma expansions.
|
|
|
+ */
|
|
|
+ spin_lock(&vma->vm_mm->page_table_lock);
|
|
|
anon_vma_interval_tree_pre_update_vma(vma);
|
|
|
vma->vm_end = address;
|
|
|
anon_vma_interval_tree_post_update_vma(vma);
|
|
@@ -2076,6 +2088,8 @@ int expand_upwards(struct vm_area_struct *vma, unsigned long address)
|
|
|
vma_gap_update(vma->vm_next);
|
|
|
else
|
|
|
vma->vm_mm->highest_vm_end = address;
|
|
|
+ spin_unlock(&vma->vm_mm->page_table_lock);
|
|
|
+
|
|
|
perf_event_mmap(vma);
|
|
|
}
|
|
|
}
|
|
@@ -2126,11 +2140,25 @@ int expand_downwards(struct vm_area_struct *vma,
|
|
|
if (grow <= vma->vm_pgoff) {
|
|
|
error = acct_stack_growth(vma, size, grow);
|
|
|
if (!error) {
|
|
|
+ /*
|
|
|
+ * vma_gap_update() doesn't support concurrent
|
|
|
+ * updates, but we only hold a shared mmap_sem
|
|
|
+ * lock here, so we need to protect against
|
|
|
+ * concurrent vma expansions.
|
|
|
+ * vma_lock_anon_vma() doesn't help here, as
|
|
|
+ * we don't guarantee that all growable vmas
|
|
|
+ * in a mm share the same root anon vma.
|
|
|
+ * So, we reuse mm->page_table_lock to guard
|
|
|
+ * against concurrent vma expansions.
|
|
|
+ */
|
|
|
+ spin_lock(&vma->vm_mm->page_table_lock);
|
|
|
anon_vma_interval_tree_pre_update_vma(vma);
|
|
|
vma->vm_start = address;
|
|
|
vma->vm_pgoff -= grow;
|
|
|
anon_vma_interval_tree_post_update_vma(vma);
|
|
|
vma_gap_update(vma);
|
|
|
+ spin_unlock(&vma->vm_mm->page_table_lock);
|
|
|
+
|
|
|
perf_event_mmap(vma);
|
|
|
}
|
|
|
}
|