diff options
author | Rik van Riel <riel@redhat.com> | 2010-08-09 20:18:39 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-08-09 23:44:55 -0400 |
commit | 5c341ee1dfc8fe69d66b1c8b19e463c6d7201ae1 (patch) | |
tree | 41f05611f8b1d7562c2193ade8c089408f262a6b /mm/rmap.c | |
parent | cba48b98f2348c814316c4b4f411a07a0e4a2bf9 (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.c | 18 |
1 files changed, 16 insertions, 2 deletions
@@ -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); |