aboutsummaryrefslogtreecommitdiffstats
path: root/mm/rmap.c
diff options
context:
space:
mode:
authorRik van Riel <riel@redhat.com>2010-08-09 20:18:41 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2010-08-09 23:44:55 -0400
commit76545066c8521f3e32c849744744842b4df25b79 (patch)
tree978b6b003f63e1e22618586b7d9c2dd8ef363614 /mm/rmap.c
parent012f18004da33ba672e3c60838cc4898126174d3 (diff)
mm: extend KSM refcounts to the anon_vma root
KSM reference counts can cause an anon_vma to exist after the processe it belongs to have already exited. Because the anon_vma lock now lives in the root anon_vma, we need to ensure that the root anon_vma stays around until after all the "child" anon_vmas have been freed. The obvious way to do this is to have a "child" anon_vma take a reference to the root in anon_vma_fork. When the anon_vma is freed at munmap or process exit, we drop the refcount in anon_vma_unlink and possibly free the root anon_vma. The KSM anon_vma reference count function also needs to be modified to deal with the possibility of freeing 2 levels of anon_vma. The easiest way to do this is to break out the KSM magic and make it generic. When compiling without CONFIG_KSM, this code is compiled out. Signed-off-by: Rik van Riel <riel@redhat.com> Tested-by: Larry Woodman <lwoodman@redhat.com> Acked-by: Larry Woodman <lwoodman@redhat.com> Reviewed-by: Minchan Kim <minchan.kim@gmail.com> Cc: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> Acked-by: Mel Gorman <mel@csn.ul.ie> Acked-by: Linus Torvalds <torvalds@linux-foundation.org> Tested-by: Dave Young <hidave.darkstar@gmail.com> 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.c46
1 files changed, 45 insertions, 1 deletions
diff --git a/mm/rmap.c b/mm/rmap.c
index caa48b27371b..07e9814c7a41 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -235,6 +235,12 @@ int anon_vma_fork(struct vm_area_struct *vma, struct vm_area_struct *pvma)
235 * lock any of the anon_vmas in this anon_vma tree. 235 * lock any of the anon_vmas in this anon_vma tree.
236 */ 236 */
237 anon_vma->root = pvma->anon_vma->root; 237 anon_vma->root = pvma->anon_vma->root;
238 /*
239 * With KSM refcounts, an anon_vma can stay around longer than the
240 * process it belongs to. The root anon_vma needs to be pinned
241 * until this anon_vma is freed, because the lock lives in the root.
242 */
243 get_anon_vma(anon_vma->root);
238 /* Mark this anon_vma as the one where our new (COWed) pages go. */ 244 /* Mark this anon_vma as the one where our new (COWed) pages go. */
239 vma->anon_vma = anon_vma; 245 vma->anon_vma = anon_vma;
240 anon_vma_chain_link(vma, avc, anon_vma); 246 anon_vma_chain_link(vma, avc, anon_vma);
@@ -264,8 +270,12 @@ static void anon_vma_unlink(struct anon_vma_chain *anon_vma_chain)
264 empty = list_empty(&anon_vma->head) && !anonvma_external_refcount(anon_vma); 270 empty = list_empty(&anon_vma->head) && !anonvma_external_refcount(anon_vma);
265 anon_vma_unlock(anon_vma); 271 anon_vma_unlock(anon_vma);
266 272
267 if (empty) 273 if (empty) {
274 /* We no longer need the root anon_vma */
275 if (anon_vma->root != anon_vma)
276 drop_anon_vma(anon_vma->root);
268 anon_vma_free(anon_vma); 277 anon_vma_free(anon_vma);
278 }
269} 279}
270 280
271void unlink_anon_vmas(struct vm_area_struct *vma) 281void unlink_anon_vmas(struct vm_area_struct *vma)
@@ -1382,6 +1392,40 @@ int try_to_munlock(struct page *page)
1382 return try_to_unmap_file(page, TTU_MUNLOCK); 1392 return try_to_unmap_file(page, TTU_MUNLOCK);
1383} 1393}
1384 1394
1395#if defined(CONFIG_KSM) || defined(CONFIG_MIGRATION)
1396/*
1397 * Drop an anon_vma refcount, freeing the anon_vma and anon_vma->root
1398 * if necessary. Be careful to do all the tests under the lock. Once
1399 * we know we are the last user, nobody else can get a reference and we
1400 * can do the freeing without the lock.
1401 */
1402void drop_anon_vma(struct anon_vma *anon_vma)
1403{
1404 if (atomic_dec_and_lock(&anon_vma->external_refcount, &anon_vma->root->lock)) {
1405 struct anon_vma *root = anon_vma->root;
1406 int empty = list_empty(&anon_vma->head);
1407 int last_root_user = 0;
1408 int root_empty = 0;
1409
1410 /*
1411 * The refcount on a non-root anon_vma got dropped. Drop
1412 * the refcount on the root and check if we need to free it.
1413 */
1414 if (empty && anon_vma != root) {
1415 last_root_user = atomic_dec_and_test(&root->external_refcount);
1416 root_empty = list_empty(&root->head);
1417 }
1418 anon_vma_unlock(anon_vma);
1419
1420 if (empty) {
1421 anon_vma_free(anon_vma);
1422 if (root_empty && last_root_user)
1423 anon_vma_free(root);
1424 }
1425 }
1426}
1427#endif
1428
1385#ifdef CONFIG_MIGRATION 1429#ifdef CONFIG_MIGRATION
1386/* 1430/*
1387 * rmap_walk() and its helpers rmap_walk_anon() and rmap_walk_file(): 1431 * rmap_walk() and its helpers rmap_walk_anon() and rmap_walk_file():