diff options
author | Hugh Dickins <hugh.dickins@tiscali.co.uk> | 2009-12-14 20:59:25 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-12-15 11:53:19 -0500 |
commit | db114b83ab6064d9b1d6ec5650e096c89bd95e25 (patch) | |
tree | 15e289b25fec011238f6838c6aafa1ff5e293224 /mm/rmap.c | |
parent | 5ad6468801d28c4d4ac9f48ec19297817c915f6a (diff) |
ksm: hold anon_vma in rmap_item
For full functionality, page_referenced_one() and try_to_unmap_one() need
to know the vma: to pass vma down to arch-dependent flushes, or to observe
VM_LOCKED or VM_EXEC. But KSM keeps no record of vma: nor can it, since
vmas get split and merged without its knowledge.
Instead, note page's anon_vma in its rmap_item when adding to stable tree:
all the vmas which might map that page are listed by its anon_vma.
page_referenced_ksm() and try_to_unmap_ksm() then traverse the anon_vma,
first to find the probable vma, that which matches rmap_item's mm; but if
that is not enough to locate all instances, traverse again to try the
others. This catches those occasions when fork has duplicated a pte of a
ksm page, but ksmd has not yet come around to assign it an rmap_item.
But each rmap_item in the stable tree which refers to an anon_vma needs to
take a reference to it. Andrea's anon_vma design cleverly avoided a
reference count (an anon_vma was free when its list of vmas was empty),
but KSM now needs to add that. Is a 32-bit count sufficient? I believe
so - the anon_vma is only free when both count is 0 and list is empty.
Signed-off-by: Hugh Dickins <hugh.dickins@tiscali.co.uk>
Cc: Izik Eidus <ieidus@redhat.com>
Cc: Andrea Arcangeli <aarcange@redhat.com>
Cc: Chris Wright <chrisw@redhat.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.c | 5 |
1 files changed, 3 insertions, 2 deletions
@@ -68,7 +68,7 @@ static inline struct anon_vma *anon_vma_alloc(void) | |||
68 | return kmem_cache_alloc(anon_vma_cachep, GFP_KERNEL); | 68 | return kmem_cache_alloc(anon_vma_cachep, GFP_KERNEL); |
69 | } | 69 | } |
70 | 70 | ||
71 | static inline void anon_vma_free(struct anon_vma *anon_vma) | 71 | void anon_vma_free(struct anon_vma *anon_vma) |
72 | { | 72 | { |
73 | kmem_cache_free(anon_vma_cachep, anon_vma); | 73 | kmem_cache_free(anon_vma_cachep, anon_vma); |
74 | } | 74 | } |
@@ -172,7 +172,7 @@ void anon_vma_unlink(struct vm_area_struct *vma) | |||
172 | list_del(&vma->anon_vma_node); | 172 | list_del(&vma->anon_vma_node); |
173 | 173 | ||
174 | /* We must garbage collect the anon_vma if it's empty */ | 174 | /* We must garbage collect the anon_vma if it's empty */ |
175 | empty = list_empty(&anon_vma->head); | 175 | empty = list_empty(&anon_vma->head) && !ksm_refcount(anon_vma); |
176 | spin_unlock(&anon_vma->lock); | 176 | spin_unlock(&anon_vma->lock); |
177 | 177 | ||
178 | if (empty) | 178 | if (empty) |
@@ -184,6 +184,7 @@ static void anon_vma_ctor(void *data) | |||
184 | struct anon_vma *anon_vma = data; | 184 | struct anon_vma *anon_vma = data; |
185 | 185 | ||
186 | spin_lock_init(&anon_vma->lock); | 186 | spin_lock_init(&anon_vma->lock); |
187 | ksm_refcount_init(anon_vma); | ||
187 | INIT_LIST_HEAD(&anon_vma->head); | 188 | INIT_LIST_HEAD(&anon_vma->head); |
188 | } | 189 | } |
189 | 190 | ||