aboutsummaryrefslogtreecommitdiffstats
path: root/mm/rmap.c
diff options
context:
space:
mode:
authorRik van Riel <riel@redhat.com>2010-08-09 20:18:39 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2010-08-09 23:44:55 -0400
commit5c341ee1dfc8fe69d66b1c8b19e463c6d7201ae1 (patch)
tree41f05611f8b1d7562c2193ade8c089408f262a6b /mm/rmap.c
parentcba48b98f2348c814316c4b4f411a07a0e4a2bf9 (diff)
mm: track the root (oldest) anon_vma
Track the root (oldest) anon_vma in each anon_vma tree. Because we only take the lock on the root anon_vma, we cannot use the lock on higher-up anon_vmas to lock anything. This makes it impossible to do an indirect lookup of the root anon_vma, since the data structures could go away from under us. However, a direct pointer is safe because the root anon_vma is always the last one that gets freed on munmap or exit, by virtue of the same_vma list order and unlink_anon_vmas walking the list forward. [akpm@linux-foundation.org: fix typo] Signed-off-by: Rik van Riel <riel@redhat.com> Acked-by: Mel Gorman <mel@csn.ul.ie> Acked-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> Tested-by: Larry Woodman <lwoodman@redhat.com> Acked-by: Larry Woodman <lwoodman@redhat.com> Reviewed-by: Minchan Kim <minchan.kim@gmail.com> Acked-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm/rmap.c')
-rw-r--r--mm/rmap.c18
1 files changed, 16 insertions, 2 deletions
diff --git a/mm/rmap.c b/mm/rmap.c
index b65f00d1707f..caa48b27371b 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -132,6 +132,11 @@ int anon_vma_prepare(struct vm_area_struct *vma)
132 if (unlikely(!anon_vma)) 132 if (unlikely(!anon_vma))
133 goto out_enomem_free_avc; 133 goto out_enomem_free_avc;
134 allocated = anon_vma; 134 allocated = anon_vma;
135 /*
136 * This VMA had no anon_vma yet. This anon_vma is
137 * the root of any anon_vma tree that might form.
138 */
139 anon_vma->root = anon_vma;
135 } 140 }
136 141
137 anon_vma_lock(anon_vma); 142 anon_vma_lock(anon_vma);
@@ -224,9 +229,15 @@ int anon_vma_fork(struct vm_area_struct *vma, struct vm_area_struct *pvma)
224 avc = anon_vma_chain_alloc(); 229 avc = anon_vma_chain_alloc();
225 if (!avc) 230 if (!avc)
226 goto out_error_free_anon_vma; 231 goto out_error_free_anon_vma;
227 anon_vma_chain_link(vma, avc, anon_vma); 232
233 /*
234 * The root anon_vma's spinlock is the lock actually used when we
235 * lock any of the anon_vmas in this anon_vma tree.
236 */
237 anon_vma->root = pvma->anon_vma->root;
228 /* Mark this anon_vma as the one where our new (COWed) pages go. */ 238 /* Mark this anon_vma as the one where our new (COWed) pages go. */
229 vma->anon_vma = anon_vma; 239 vma->anon_vma = anon_vma;
240 anon_vma_chain_link(vma, avc, anon_vma);
230 241
231 return 0; 242 return 0;
232 243
@@ -261,7 +272,10 @@ void unlink_anon_vmas(struct vm_area_struct *vma)
261{ 272{
262 struct anon_vma_chain *avc, *next; 273 struct anon_vma_chain *avc, *next;
263 274
264 /* Unlink each anon_vma chained to the VMA. */ 275 /*
276 * Unlink each anon_vma chained to the VMA. This list is ordered
277 * from newest to oldest, ensuring the root anon_vma gets freed last.
278 */
265 list_for_each_entry_safe(avc, next, &vma->anon_vma_chain, same_vma) { 279 list_for_each_entry_safe(avc, next, &vma->anon_vma_chain, same_vma) {
266 anon_vma_unlink(avc); 280 anon_vma_unlink(avc);
267 list_del(&avc->same_vma); 281 list_del(&avc->same_vma);