diff options
Diffstat (limited to 'mm/huge_memory.c')
| -rw-r--r-- | mm/huge_memory.c | 15 | 
1 files changed, 13 insertions, 2 deletions
diff --git a/mm/huge_memory.c b/mm/huge_memory.c index 9e894edc781..6001ee6347a 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -1819,9 +1819,19 @@ int split_huge_page(struct page *page)  	BUG_ON(is_huge_zero_pfn(page_to_pfn(page)));  	BUG_ON(!PageAnon(page)); -	anon_vma = page_lock_anon_vma_read(page); + +	/* +	 * The caller does not necessarily hold an mmap_sem that would prevent +	 * the anon_vma disappearing so we first we take a reference to it +	 * and then lock the anon_vma for write. This is similar to +	 * page_lock_anon_vma_read except the write lock is taken to serialise +	 * against parallel split or collapse operations. +	 */ +	anon_vma = page_get_anon_vma(page);  	if (!anon_vma)  		goto out; +	anon_vma_lock_write(anon_vma); +  	ret = 0;  	if (!PageCompound(page))  		goto out_unlock; @@ -1832,7 +1842,8 @@ int split_huge_page(struct page *page)  	BUG_ON(PageCompound(page));  out_unlock: -	page_unlock_anon_vma_read(anon_vma); +	anon_vma_unlock(anon_vma); +	put_anon_vma(anon_vma);  out:  	return ret;  }  |