/* This must be called under the mmap_sem. */ int anon_vma_prepare(struct vm_area_struct *vma) { struct anon_vma *anon_vma = vma->anon_vma; might_sleep(); if (unlikely(!anon_vma)) { struct mm_struct *mm = vma->vm_mm; struct anon_vma *allocated, *locked; anon_vma = find_mergeable_anon_vma(vma); if (anon_vma) { allocated = NULL; locked = anon_vma; spin_lock(&locked->lock); } else { anon_vma = anon_vma_alloc(); if (unlikely(!anon_vma)) return -ENOMEM; allocated = anon_vma; locked = NULL; } /* page_table_lock to protect against threads */ spin_lock(&mm->page_table_lock); if (likely(!vma->anon_vma)) { vma->anon_vma = anon_vma; list_add(&vma->anon_vma_node, &anon_vma->head); allocated = NULL; } #ifdef CONFIG_PAX_SEGMEXEC if (vma->vm_flags & VM_MIRROR) { struct vm_area_struct *vma_m; vma_m = find_vma(vma->vm_mm, vma->vm_start + vma->vm_mirror); BUG_ON(!vma_m || vma_m->vm_start != vma->vm_start + vma->vm_mirror); BUG_ON(vma_m->anon_vma || vma->vm_pgoff != vma_m->vm_pgoff); vma_m->anon_vma = anon_vma; __anon_vma_link(vma_m); } #endif spin_unlock(&mm->page_table_lock); if (locked) spin_unlock(&locked->lock); if (unlikely(allocated)) anon_vma_free(allocated); } return 0; }