aboutsummaryrefslogtreecommitdiffstats
path: root/include/linux/rmap.h
diff options
context:
space:
mode:
authorHugh Dickins <hugh.dickins@tiscali.co.uk>2009-12-14 20:59:25 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2009-12-15 11:53:19 -0500
commitdb114b83ab6064d9b1d6ec5650e096c89bd95e25 (patch)
tree15e289b25fec011238f6838c6aafa1ff5e293224 /include/linux/rmap.h
parent5ad6468801d28c4d4ac9f48ec19297817c915f6a (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 'include/linux/rmap.h')
-rw-r--r--include/linux/rmap.h24
1 files changed, 24 insertions, 0 deletions
diff --git a/include/linux/rmap.h b/include/linux/rmap.h
index 0b4913a4a344..980094a527ee 100644
--- a/include/linux/rmap.h
+++ b/include/linux/rmap.h
@@ -26,6 +26,9 @@
26 */ 26 */
27struct anon_vma { 27struct anon_vma {
28 spinlock_t lock; /* Serialize access to vma list */ 28 spinlock_t lock; /* Serialize access to vma list */
29#ifdef CONFIG_KSM
30 atomic_t ksm_refcount;
31#endif
29 /* 32 /*
30 * NOTE: the LSB of the head.next is set by 33 * NOTE: the LSB of the head.next is set by
31 * mm_take_all_locks() _after_ taking the above lock. So the 34 * mm_take_all_locks() _after_ taking the above lock. So the
@@ -38,6 +41,26 @@ struct anon_vma {
38}; 41};
39 42
40#ifdef CONFIG_MMU 43#ifdef CONFIG_MMU
44#ifdef CONFIG_KSM
45static inline void ksm_refcount_init(struct anon_vma *anon_vma)
46{
47 atomic_set(&anon_vma->ksm_refcount, 0);
48}
49
50static inline int ksm_refcount(struct anon_vma *anon_vma)
51{
52 return atomic_read(&anon_vma->ksm_refcount);
53}
54#else
55static inline void ksm_refcount_init(struct anon_vma *anon_vma)
56{
57}
58
59static inline int ksm_refcount(struct anon_vma *anon_vma)
60{
61 return 0;
62}
63#endif /* CONFIG_KSM */
41 64
42static inline struct anon_vma *page_anon_vma(struct page *page) 65static inline struct anon_vma *page_anon_vma(struct page *page)
43{ 66{
@@ -70,6 +93,7 @@ void __anon_vma_merge(struct vm_area_struct *, struct vm_area_struct *);
70void anon_vma_unlink(struct vm_area_struct *); 93void anon_vma_unlink(struct vm_area_struct *);
71void anon_vma_link(struct vm_area_struct *); 94void anon_vma_link(struct vm_area_struct *);
72void __anon_vma_link(struct vm_area_struct *); 95void __anon_vma_link(struct vm_area_struct *);
96void anon_vma_free(struct anon_vma *);
73 97
74/* 98/*
75 * rmap interfaces called when adding or removing pte of page 99 * rmap interfaces called when adding or removing pte of page