diff options
author | Rik van Riel <riel@redhat.com> | 2010-08-09 20:18:41 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-08-09 23:44:55 -0400 |
commit | 76545066c8521f3e32c849744744842b4df25b79 (patch) | |
tree | 978b6b003f63e1e22618586b7d9c2dd8ef363614 /mm/migrate.c | |
parent | 012f18004da33ba672e3c60838cc4898126174d3 (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/migrate.c')
-rw-r--r-- | mm/migrate.c | 10 |
1 files changed, 3 insertions, 7 deletions
diff --git a/mm/migrate.c b/mm/migrate.c index 5208fa1d9712..38e7cad782f4 100644 --- a/mm/migrate.c +++ b/mm/migrate.c | |||
@@ -639,7 +639,7 @@ static int unmap_and_move(new_page_t get_new_page, unsigned long private, | |||
639 | * exist when the page is remapped later | 639 | * exist when the page is remapped later |
640 | */ | 640 | */ |
641 | anon_vma = page_anon_vma(page); | 641 | anon_vma = page_anon_vma(page); |
642 | atomic_inc(&anon_vma->external_refcount); | 642 | get_anon_vma(anon_vma); |
643 | } | 643 | } |
644 | } | 644 | } |
645 | 645 | ||
@@ -682,12 +682,8 @@ skip_unmap: | |||
682 | rcu_unlock: | 682 | rcu_unlock: |
683 | 683 | ||
684 | /* Drop an anon_vma reference if we took one */ | 684 | /* Drop an anon_vma reference if we took one */ |
685 | if (anon_vma && atomic_dec_and_lock(&anon_vma->external_refcount, &anon_vma->root->lock)) { | 685 | if (anon_vma) |
686 | int empty = list_empty(&anon_vma->head); | 686 | drop_anon_vma(anon_vma); |
687 | anon_vma_unlock(anon_vma); | ||
688 | if (empty) | ||
689 | anon_vma_free(anon_vma); | ||
690 | } | ||
691 | 687 | ||
692 | if (rcu_locked) | 688 | if (rcu_locked) |
693 | rcu_read_unlock(); | 689 | rcu_read_unlock(); |