diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-04-12 18:39:58 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-04-12 18:39:58 -0700 |
commit | 64a8920fab962fb581bbe67856cb4740fc37d743 (patch) | |
tree | a569ffc6d02994a899e4855eda71001d665a80a8 /mm/rmap.c | |
parent | 50b88c46f01939d19d4cdd30ad563d29265b6c59 (diff) | |
parent | ea90002b0fa7bdee86ec22eba1d951f30bf043a6 (diff) |
Merge branch 'anonvma'
* anonvma:
anonvma: when setting up page->mapping, we need to pick the _oldest_ anonvma
anon_vma: clone the anon_vma chain in the right order
vma_adjust: fix the copying of anon_vma chains
Simplify and comment on anon_vma re-use for anon_vma_prepare()
Diffstat (limited to 'mm/rmap.c')
-rw-r--r-- | mm/rmap.c | 17 |
1 files changed, 14 insertions, 3 deletions
diff --git a/mm/rmap.c b/mm/rmap.c index eaa7a09eb72e..4bad3267537a 100644 --- a/mm/rmap.c +++ b/mm/rmap.c @@ -182,7 +182,7 @@ int anon_vma_clone(struct vm_area_struct *dst, struct vm_area_struct *src) { struct anon_vma_chain *avc, *pavc; - list_for_each_entry(pavc, &src->anon_vma_chain, same_vma) { + list_for_each_entry_reverse(pavc, &src->anon_vma_chain, same_vma) { avc = anon_vma_chain_alloc(); if (!avc) goto enomem_failure; @@ -734,9 +734,20 @@ void page_move_anon_rmap(struct page *page, static void __page_set_anon_rmap(struct page *page, struct vm_area_struct *vma, unsigned long address) { - struct anon_vma *anon_vma = vma->anon_vma; + struct anon_vma_chain *avc; + struct anon_vma *anon_vma; + + BUG_ON(!vma->anon_vma); + + /* + * We must use the _oldest_ possible anon_vma for the page mapping! + * + * So take the last AVC chain entry in the vma, which is the deepest + * ancestor, and use the anon_vma from that. + */ + avc = list_entry(vma->anon_vma_chain.prev, struct anon_vma_chain, same_vma); + anon_vma = avc->anon_vma; - BUG_ON(!anon_vma); anon_vma = (void *) anon_vma + PAGE_MAPPING_ANON; page->mapping = (struct address_space *) anon_vma; page->index = linear_page_index(vma, address); |