diff options
author | Andrea Arcangeli <aarcange@redhat.com> | 2011-01-13 18:46:53 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-01-13 20:32:42 -0500 |
commit | 05759d380a9d7f131a475186c07fce58ceaa8902 (patch) | |
tree | 6c253f15176c89f6f8dfd80b1471bcf3e0a3e44e | |
parent | 8a07651ee8cdaa9e27cb4ae372aed347533770f5 (diff) |
thp: split_huge_page anon_vma ordering dependency
This documents how split_huge_page is safe vs new vma inserctions into the
anon_vma that may have already released the anon_vma->lock but not
established pmds yet when split_huge_page starts.
Signed-off-by: Andrea Arcangeli <aarcange@redhat.com>
Acked-by: Mel Gorman <mel@csn.ul.ie>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | mm/huge_memory.c | 16 | ||||
-rw-r--r-- | mm/rmap.c | 4 |
2 files changed, 20 insertions, 0 deletions
diff --git a/mm/huge_memory.c b/mm/huge_memory.c index 0c1e8f939f7c..763507932898 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c | |||
@@ -841,6 +841,19 @@ static void __split_huge_page(struct page *page, | |||
841 | continue; | 841 | continue; |
842 | mapcount += __split_huge_page_splitting(page, vma, addr); | 842 | mapcount += __split_huge_page_splitting(page, vma, addr); |
843 | } | 843 | } |
844 | /* | ||
845 | * It is critical that new vmas are added to the tail of the | ||
846 | * anon_vma list. This guarantes that if copy_huge_pmd() runs | ||
847 | * and establishes a child pmd before | ||
848 | * __split_huge_page_splitting() freezes the parent pmd (so if | ||
849 | * we fail to prevent copy_huge_pmd() from running until the | ||
850 | * whole __split_huge_page() is complete), we will still see | ||
851 | * the newly established pmd of the child later during the | ||
852 | * walk, to be able to set it as pmd_trans_splitting too. | ||
853 | */ | ||
854 | if (mapcount != page_mapcount(page)) | ||
855 | printk(KERN_ERR "mapcount %d page_mapcount %d\n", | ||
856 | mapcount, page_mapcount(page)); | ||
844 | BUG_ON(mapcount != page_mapcount(page)); | 857 | BUG_ON(mapcount != page_mapcount(page)); |
845 | 858 | ||
846 | __split_huge_page_refcount(page); | 859 | __split_huge_page_refcount(page); |
@@ -854,6 +867,9 @@ static void __split_huge_page(struct page *page, | |||
854 | continue; | 867 | continue; |
855 | mapcount2 += __split_huge_page_map(page, vma, addr); | 868 | mapcount2 += __split_huge_page_map(page, vma, addr); |
856 | } | 869 | } |
870 | if (mapcount != mapcount2) | ||
871 | printk(KERN_ERR "mapcount %d mapcount2 %d page_mapcount %d\n", | ||
872 | mapcount, mapcount2, page_mapcount(page)); | ||
857 | BUG_ON(mapcount != mapcount2); | 873 | BUG_ON(mapcount != mapcount2); |
858 | } | 874 | } |
859 | 875 | ||
@@ -177,6 +177,10 @@ static void anon_vma_chain_link(struct vm_area_struct *vma, | |||
177 | list_add(&avc->same_vma, &vma->anon_vma_chain); | 177 | list_add(&avc->same_vma, &vma->anon_vma_chain); |
178 | 178 | ||
179 | anon_vma_lock(anon_vma); | 179 | anon_vma_lock(anon_vma); |
180 | /* | ||
181 | * It's critical to add new vmas to the tail of the anon_vma, | ||
182 | * see comment in huge_memory.c:__split_huge_page(). | ||
183 | */ | ||
180 | list_add_tail(&avc->same_anon_vma, &anon_vma->head); | 184 | list_add_tail(&avc->same_anon_vma, &anon_vma->head); |
181 | anon_vma_unlock(anon_vma); | 185 | anon_vma_unlock(anon_vma); |
182 | } | 186 | } |