diff options
author | Andrea Arcangeli <aarcange@redhat.com> | 2011-01-13 15:46:53 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-01-13 17:32:42 -0800 |
commit | 05759d380a9d7f131a475186c07fce58ceaa8902 (patch) | |
tree | 6c253f15176c89f6f8dfd80b1471bcf3e0a3e44e /mm/huge_memory.c | |
parent | 8a07651ee8cdaa9e27cb4ae372aed347533770f5 (diff) | |
download | linux-rpi-05759d380a9d7f131a475186c07fce58ceaa8902.tar.gz linux-rpi-05759d380a9d7f131a475186c07fce58ceaa8902.tar.bz2 linux-rpi-05759d380a9d7f131a475186c07fce58ceaa8902.zip |
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>
Diffstat (limited to 'mm/huge_memory.c')
-rw-r--r-- | mm/huge_memory.c | 16 |
1 files changed, 16 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, continue; mapcount += __split_huge_page_splitting(page, vma, addr); } + /* + * It is critical that new vmas are added to the tail of the + * anon_vma list. This guarantes that if copy_huge_pmd() runs + * and establishes a child pmd before + * __split_huge_page_splitting() freezes the parent pmd (so if + * we fail to prevent copy_huge_pmd() from running until the + * whole __split_huge_page() is complete), we will still see + * the newly established pmd of the child later during the + * walk, to be able to set it as pmd_trans_splitting too. + */ + if (mapcount != page_mapcount(page)) + printk(KERN_ERR "mapcount %d page_mapcount %d\n", + mapcount, page_mapcount(page)); BUG_ON(mapcount != page_mapcount(page)); __split_huge_page_refcount(page); @@ -854,6 +867,9 @@ static void __split_huge_page(struct page *page, continue; mapcount2 += __split_huge_page_map(page, vma, addr); } + if (mapcount != mapcount2) + printk(KERN_ERR "mapcount %d mapcount2 %d page_mapcount %d\n", + mapcount, mapcount2, page_mapcount(page)); BUG_ON(mapcount != mapcount2); } |