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 9e894edc7811..6001ee6347a9 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c | |||
@@ -1819,9 +1819,19 @@ int split_huge_page(struct page *page) | |||
1819 | 1819 | ||
1820 | BUG_ON(is_huge_zero_pfn(page_to_pfn(page))); | 1820 | BUG_ON(is_huge_zero_pfn(page_to_pfn(page))); |
1821 | BUG_ON(!PageAnon(page)); | 1821 | BUG_ON(!PageAnon(page)); |
1822 | anon_vma = page_lock_anon_vma_read(page); | 1822 | |
1823 | /* | ||
1824 | * The caller does not necessarily hold an mmap_sem that would prevent | ||
1825 | * the anon_vma disappearing so we first we take a reference to it | ||
1826 | * and then lock the anon_vma for write. This is similar to | ||
1827 | * page_lock_anon_vma_read except the write lock is taken to serialise | ||
1828 | * against parallel split or collapse operations. | ||
1829 | */ | ||
1830 | anon_vma = page_get_anon_vma(page); | ||
1823 | if (!anon_vma) | 1831 | if (!anon_vma) |
1824 | goto out; | 1832 | goto out; |
1833 | anon_vma_lock_write(anon_vma); | ||
1834 | |||
1825 | ret = 0; | 1835 | ret = 0; |
1826 | if (!PageCompound(page)) | 1836 | if (!PageCompound(page)) |
1827 | goto out_unlock; | 1837 | goto out_unlock; |
@@ -1832,7 +1842,8 @@ int split_huge_page(struct page *page) | |||
1832 | 1842 | ||
1833 | BUG_ON(PageCompound(page)); | 1843 | BUG_ON(PageCompound(page)); |
1834 | out_unlock: | 1844 | out_unlock: |
1835 | page_unlock_anon_vma_read(anon_vma); | 1845 | anon_vma_unlock(anon_vma); |
1846 | put_anon_vma(anon_vma); | ||
1836 | out: | 1847 | out: |
1837 | return ret; | 1848 | return ret; |
1838 | } | 1849 | } |