diff options
Diffstat (limited to 'mm/rmap.c')
-rw-r--r-- | mm/rmap.c | 17 |
1 files changed, 14 insertions, 3 deletions
@@ -182,7 +182,7 @@ int anon_vma_clone(struct vm_area_struct *dst, struct vm_area_struct *src) | |||
182 | { | 182 | { |
183 | struct anon_vma_chain *avc, *pavc; | 183 | struct anon_vma_chain *avc, *pavc; |
184 | 184 | ||
185 | list_for_each_entry(pavc, &src->anon_vma_chain, same_vma) { | 185 | list_for_each_entry_reverse(pavc, &src->anon_vma_chain, same_vma) { |
186 | avc = anon_vma_chain_alloc(); | 186 | avc = anon_vma_chain_alloc(); |
187 | if (!avc) | 187 | if (!avc) |
188 | goto enomem_failure; | 188 | goto enomem_failure; |
@@ -734,9 +734,20 @@ void page_move_anon_rmap(struct page *page, | |||
734 | static void __page_set_anon_rmap(struct page *page, | 734 | static void __page_set_anon_rmap(struct page *page, |
735 | struct vm_area_struct *vma, unsigned long address) | 735 | struct vm_area_struct *vma, unsigned long address) |
736 | { | 736 | { |
737 | struct anon_vma *anon_vma = vma->anon_vma; | 737 | struct anon_vma_chain *avc; |
738 | struct anon_vma *anon_vma; | ||
739 | |||
740 | BUG_ON(!vma->anon_vma); | ||
741 | |||
742 | /* | ||
743 | * We must use the _oldest_ possible anon_vma for the page mapping! | ||
744 | * | ||
745 | * So take the last AVC chain entry in the vma, which is the deepest | ||
746 | * ancestor, and use the anon_vma from that. | ||
747 | */ | ||
748 | avc = list_entry(vma->anon_vma_chain.prev, struct anon_vma_chain, same_vma); | ||
749 | anon_vma = avc->anon_vma; | ||
738 | 750 | ||
739 | BUG_ON(!anon_vma); | ||
740 | anon_vma = (void *) anon_vma + PAGE_MAPPING_ANON; | 751 | anon_vma = (void *) anon_vma + PAGE_MAPPING_ANON; |
741 | page->mapping = (struct address_space *) anon_vma; | 752 | page->mapping = (struct address_space *) anon_vma; |
742 | page->index = linear_page_index(vma, address); | 753 | page->index = linear_page_index(vma, address); |