From 149df5d45a4b33f42a6c5ee6b6080abaa2eec71d Mon Sep 17 00:00:00 2001 From: Rik van Riel Date: Mon, 9 Aug 2010 17:18:39 -0700 Subject: [PATCH] --- yaml --- r: 207198 b: refs/heads/master c: 5c341ee1dfc8fe69d66b1c8b19e463c6d7201ae1 h: refs/heads/master v: v3 --- [refs] | 2 +- trunk/include/linux/rmap.h | 1 + trunk/mm/rmap.c | 18 ++++++++++++++++-- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/[refs] b/[refs] index 630f3fbe16a1..5d52f92a1ba8 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: cba48b98f2348c814316c4b4f411a07a0e4a2bf9 +refs/heads/master: 5c341ee1dfc8fe69d66b1c8b19e463c6d7201ae1 diff --git a/trunk/include/linux/rmap.h b/trunk/include/linux/rmap.h index 5f981be61416..41fa6ddc6214 100644 --- a/trunk/include/linux/rmap.h +++ b/trunk/include/linux/rmap.h @@ -26,6 +26,7 @@ */ struct anon_vma { spinlock_t lock; /* Serialize access to vma list */ + struct anon_vma *root; /* Root of this anon_vma tree */ #if defined(CONFIG_KSM) || defined(CONFIG_MIGRATION) /* diff --git a/trunk/mm/rmap.c b/trunk/mm/rmap.c index b65f00d1707f..caa48b27371b 100644 --- a/trunk/mm/rmap.c +++ b/trunk/mm/rmap.c @@ -132,6 +132,11 @@ int anon_vma_prepare(struct vm_area_struct *vma) if (unlikely(!anon_vma)) goto out_enomem_free_avc; allocated = anon_vma; + /* + * This VMA had no anon_vma yet. This anon_vma is + * the root of any anon_vma tree that might form. + */ + anon_vma->root = anon_vma; } anon_vma_lock(anon_vma); @@ -224,9 +229,15 @@ int anon_vma_fork(struct vm_area_struct *vma, struct vm_area_struct *pvma) avc = anon_vma_chain_alloc(); if (!avc) goto out_error_free_anon_vma; - anon_vma_chain_link(vma, avc, anon_vma); + + /* + * The root anon_vma's spinlock is the lock actually used when we + * lock any of the anon_vmas in this anon_vma tree. + */ + anon_vma->root = pvma->anon_vma->root; /* Mark this anon_vma as the one where our new (COWed) pages go. */ vma->anon_vma = anon_vma; + anon_vma_chain_link(vma, avc, anon_vma); return 0; @@ -261,7 +272,10 @@ void unlink_anon_vmas(struct vm_area_struct *vma) { struct anon_vma_chain *avc, *next; - /* Unlink each anon_vma chained to the VMA. */ + /* + * Unlink each anon_vma chained to the VMA. This list is ordered + * from newest to oldest, ensuring the root anon_vma gets freed last. + */ list_for_each_entry_safe(avc, next, &vma->anon_vma_chain, same_vma) { anon_vma_unlink(avc); list_del(&avc->same_vma);