hugetlb: acquire the i_mmap_lock before walking the prio_tree to unmap a page
When the owner of a mapping fails COW because a child process is holding a reference, the children VMAs are walked and the page is unmapped. The i_mmap_lock is taken for the unmapping of the page but not the walking of the prio_tree. In theory, that tree could be changing if the lock is not held. This patch takes the i_mmap_lock properly for the duration of the prio_tree walk. [hugh.dickins@tiscali.co.uk: Spotted the problem in the first place] Signed-off-by: Mel Gorman <mel@csn.ul.ie> Acked-by: Hugh Dickins <hugh.dickins@tiscali.co.uk> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
70da2340fb
commit
4eb2b1dcd5
1 changed files with 8 additions and 1 deletions
|
@ -2237,6 +2237,12 @@ static int unmap_ref_private(struct mm_struct *mm, struct vm_area_struct *vma,
|
|||
+ (vma->vm_pgoff >> PAGE_SHIFT);
|
||||
mapping = (struct address_space *)page_private(page);
|
||||
|
||||
/*
|
||||
* Take the mapping lock for the duration of the table walk. As
|
||||
* this mapping should be shared between all the VMAs,
|
||||
* __unmap_hugepage_range() is called as the lock is already held
|
||||
*/
|
||||
spin_lock(&mapping->i_mmap_lock);
|
||||
vma_prio_tree_foreach(iter_vma, &iter, &mapping->i_mmap, pgoff, pgoff) {
|
||||
/* Do not unmap the current VMA */
|
||||
if (iter_vma == vma)
|
||||
|
@ -2250,10 +2256,11 @@ static int unmap_ref_private(struct mm_struct *mm, struct vm_area_struct *vma,
|
|||
* from the time of fork. This would look like data corruption
|
||||
*/
|
||||
if (!is_vma_resv_set(iter_vma, HPAGE_RESV_OWNER))
|
||||
unmap_hugepage_range(iter_vma,
|
||||
__unmap_hugepage_range(iter_vma,
|
||||
address, address + huge_page_size(h),
|
||||
page);
|
||||
}
|
||||
spin_unlock(&mapping->i_mmap_lock);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue