summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrea Arcangeli <aarcange@redhat.com>2010-08-02 20:40:46 +0200
committerAndrea Arcangeli <aarcange@redhat.com>2010-08-02 18:43:04 +0000
commit5e075da490ca5ba85b520134ca42640a18f6edf5 (patch)
tree98d4446d4c0c975e5ab75f6c3f4f378b929f0e97
parent213c1ddbdb137e0d21fda824a67402d2109e1958 (diff)
root anon vma use root
Always use anon_vma->root pointer instead of anon_vma_chain.prev. Also optimize the map-paths, if a mapping is already established no need to overwrite it with root anon-vma list, we can keep the more finegrined anon-vma and skip the overwrite: see the PageAnon check in !exclusive case. This is also the optimization that hidden the ksm bug as this tends to make ksm_might_need_to_copy skip the copy, but only the proper fix to ksm_might_need_to_copy guarantees not triggering the ksm bug unless ksm is in use. this is an optimization only... Signed-off-by: Andrea Arcangeli <aarcange@redhat.com>
-rw-r--r--mm/rmap.c23
1 files changed, 7 insertions, 16 deletions
diff --git a/mm/rmap.c b/mm/rmap.c
index bc665c218406..8fbb312b0e0e 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -208,7 +208,7 @@ int anon_vma_clone(struct vm_area_struct *dst, struct vm_area_struct *src)
*/
int anon_vma_fork(struct vm_area_struct *vma, struct vm_area_struct *pvma)
{
- struct anon_vma_chain *avc, *root_avc;
+ struct anon_vma_chain *avc;
struct anon_vma *anon_vma;
/* Don't bother if the parent process has no anon_vma here. */
@@ -230,14 +230,7 @@ int anon_vma_fork(struct vm_area_struct *vma, struct vm_area_struct *pvma)
if (!avc)
goto out_error_free_anon_vma;
- /*
- * Get the root anon_vma on the list by depending on the ordering
- * of the same_vma list setup by previous invocations of anon_vma_fork.
- * The root anon_vma will always be referenced by the last item
- * in the anon_vma_chain list.
- */
- root_avc = list_entry(vma->anon_vma_chain.prev, struct anon_vma_chain, same_vma);
- anon_vma->root = root_avc->anon_vma;
+ anon_vma->root = pvma->anon_vma->root;
/*
* With KSM refcounts, an anon_vma can stay around longer than the
* process it belongs to. The root anon_vma needs to be pinned
@@ -768,15 +761,13 @@ static void __page_set_anon_rmap(struct page *page,
* If the page isn't exclusively mapped into this 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.
*/
if (!exclusive) {
- struct anon_vma_chain *avc;
- avc = list_entry(vma->anon_vma_chain.prev, struct anon_vma_chain, same_vma);
- anon_vma = avc->anon_vma;
- }
+ if (PageAnon(page))
+ return;
+ anon_vma = anon_vma->root;
+ } else
+ BUG_ON(PageAnon(page));
anon_vma = (void *) anon_vma + PAGE_MAPPING_ANON;
page->mapping = (struct address_space *) anon_vma;