diff options
Diffstat (limited to 'include/linux/rmap.h')
| -rw-r--r-- | include/linux/rmap.h | 106 |
1 files changed, 88 insertions, 18 deletions
diff --git a/include/linux/rmap.h b/include/linux/rmap.h index b019ae64e2ab..31b2fd75dcba 100644 --- a/include/linux/rmap.h +++ b/include/linux/rmap.h | |||
| @@ -26,8 +26,18 @@ | |||
| 26 | */ | 26 | */ |
| 27 | struct anon_vma { | 27 | struct anon_vma { |
| 28 | spinlock_t lock; /* Serialize access to vma list */ | 28 | spinlock_t lock; /* Serialize access to vma list */ |
| 29 | #ifdef CONFIG_KSM | 29 | struct anon_vma *root; /* Root of this anon_vma tree */ |
| 30 | atomic_t ksm_refcount; | 30 | #if defined(CONFIG_KSM) || defined(CONFIG_MIGRATION) |
| 31 | |||
| 32 | /* | ||
| 33 | * The external_refcount is taken by either KSM or page migration | ||
| 34 | * to take a reference to an anon_vma when there is no | ||
| 35 | * guarantee that the vma of page tables will exist for | ||
| 36 | * the duration of the operation. A caller that takes | ||
| 37 | * the reference is responsible for clearing up the | ||
| 38 | * anon_vma if they are the last user on release | ||
| 39 | */ | ||
| 40 | atomic_t external_refcount; | ||
| 31 | #endif | 41 | #endif |
| 32 | /* | 42 | /* |
| 33 | * NOTE: the LSB of the head.next is set by | 43 | * NOTE: the LSB of the head.next is set by |
| @@ -37,29 +47,64 @@ struct anon_vma { | |||
| 37 | * is serialized by a system wide lock only visible to | 47 | * is serialized by a system wide lock only visible to |
| 38 | * mm_take_all_locks() (mm_all_locks_mutex). | 48 | * mm_take_all_locks() (mm_all_locks_mutex). |
| 39 | */ | 49 | */ |
| 40 | struct list_head head; /* List of private "related" vmas */ | 50 | struct list_head head; /* Chain of private "related" vmas */ |
| 51 | }; | ||
| 52 | |||
| 53 | /* | ||
| 54 | * The copy-on-write semantics of fork mean that an anon_vma | ||
| 55 | * can become associated with multiple processes. Furthermore, | ||
| 56 | * each child process will have its own anon_vma, where new | ||
| 57 | * pages for that process are instantiated. | ||
| 58 | * | ||
| 59 | * This structure allows us to find the anon_vmas associated | ||
| 60 | * with a VMA, or the VMAs associated with an anon_vma. | ||
| 61 | * The "same_vma" list contains the anon_vma_chains linking | ||
| 62 | * all the anon_vmas associated with this VMA. | ||
| 63 | * The "same_anon_vma" list contains the anon_vma_chains | ||
| 64 | * which link all the VMAs associated with this anon_vma. | ||
| 65 | */ | ||
| 66 | struct anon_vma_chain { | ||
| 67 | struct vm_area_struct *vma; | ||
| 68 | struct anon_vma *anon_vma; | ||
| 69 | struct list_head same_vma; /* locked by mmap_sem & page_table_lock */ | ||
| 70 | struct list_head same_anon_vma; /* locked by anon_vma->lock */ | ||
| 41 | }; | 71 | }; |
| 42 | 72 | ||
| 43 | #ifdef CONFIG_MMU | 73 | #ifdef CONFIG_MMU |
| 44 | #ifdef CONFIG_KSM | 74 | #if defined(CONFIG_KSM) || defined(CONFIG_MIGRATION) |
| 45 | static inline void ksm_refcount_init(struct anon_vma *anon_vma) | 75 | static inline void anonvma_external_refcount_init(struct anon_vma *anon_vma) |
| 46 | { | 76 | { |
| 47 | atomic_set(&anon_vma->ksm_refcount, 0); | 77 | atomic_set(&anon_vma->external_refcount, 0); |
| 48 | } | 78 | } |
| 49 | 79 | ||
| 50 | static inline int ksm_refcount(struct anon_vma *anon_vma) | 80 | static inline int anonvma_external_refcount(struct anon_vma *anon_vma) |
| 51 | { | 81 | { |
| 52 | return atomic_read(&anon_vma->ksm_refcount); | 82 | return atomic_read(&anon_vma->external_refcount); |
| 53 | } | 83 | } |
| 84 | |||
| 85 | static inline void get_anon_vma(struct anon_vma *anon_vma) | ||
| 86 | { | ||
| 87 | atomic_inc(&anon_vma->external_refcount); | ||
| 88 | } | ||
| 89 | |||
| 90 | void drop_anon_vma(struct anon_vma *); | ||
| 54 | #else | 91 | #else |
| 55 | static inline void ksm_refcount_init(struct anon_vma *anon_vma) | 92 | static inline void anonvma_external_refcount_init(struct anon_vma *anon_vma) |
| 56 | { | 93 | { |
| 57 | } | 94 | } |
| 58 | 95 | ||
| 59 | static inline int ksm_refcount(struct anon_vma *anon_vma) | 96 | static inline int anonvma_external_refcount(struct anon_vma *anon_vma) |
| 60 | { | 97 | { |
| 61 | return 0; | 98 | return 0; |
| 62 | } | 99 | } |
| 100 | |||
| 101 | static inline void get_anon_vma(struct anon_vma *anon_vma) | ||
| 102 | { | ||
| 103 | } | ||
| 104 | |||
| 105 | static inline void drop_anon_vma(struct anon_vma *anon_vma) | ||
| 106 | { | ||
| 107 | } | ||
| 63 | #endif /* CONFIG_KSM */ | 108 | #endif /* CONFIG_KSM */ |
| 64 | 109 | ||
| 65 | static inline struct anon_vma *page_anon_vma(struct page *page) | 110 | static inline struct anon_vma *page_anon_vma(struct page *page) |
| @@ -70,18 +115,28 @@ static inline struct anon_vma *page_anon_vma(struct page *page) | |||
| 70 | return page_rmapping(page); | 115 | return page_rmapping(page); |
| 71 | } | 116 | } |
| 72 | 117 | ||
| 73 | static inline void anon_vma_lock(struct vm_area_struct *vma) | 118 | static inline void vma_lock_anon_vma(struct vm_area_struct *vma) |
| 74 | { | 119 | { |
| 75 | struct anon_vma *anon_vma = vma->anon_vma; | 120 | struct anon_vma *anon_vma = vma->anon_vma; |
| 76 | if (anon_vma) | 121 | if (anon_vma) |
| 77 | spin_lock(&anon_vma->lock); | 122 | spin_lock(&anon_vma->root->lock); |
| 78 | } | 123 | } |
| 79 | 124 | ||
| 80 | static inline void anon_vma_unlock(struct vm_area_struct *vma) | 125 | static inline void vma_unlock_anon_vma(struct vm_area_struct *vma) |
| 81 | { | 126 | { |
| 82 | struct anon_vma *anon_vma = vma->anon_vma; | 127 | struct anon_vma *anon_vma = vma->anon_vma; |
| 83 | if (anon_vma) | 128 | if (anon_vma) |
| 84 | spin_unlock(&anon_vma->lock); | 129 | spin_unlock(&anon_vma->root->lock); |
| 130 | } | ||
| 131 | |||
| 132 | static inline void anon_vma_lock(struct anon_vma *anon_vma) | ||
| 133 | { | ||
| 134 | spin_lock(&anon_vma->root->lock); | ||
| 135 | } | ||
| 136 | |||
| 137 | static inline void anon_vma_unlock(struct anon_vma *anon_vma) | ||
| 138 | { | ||
| 139 | spin_unlock(&anon_vma->root->lock); | ||
| 85 | } | 140 | } |
| 86 | 141 | ||
| 87 | /* | 142 | /* |
| @@ -89,20 +144,35 @@ static inline void anon_vma_unlock(struct vm_area_struct *vma) | |||
| 89 | */ | 144 | */ |
| 90 | void anon_vma_init(void); /* create anon_vma_cachep */ | 145 | void anon_vma_init(void); /* create anon_vma_cachep */ |
| 91 | int anon_vma_prepare(struct vm_area_struct *); | 146 | int anon_vma_prepare(struct vm_area_struct *); |
| 92 | void __anon_vma_merge(struct vm_area_struct *, struct vm_area_struct *); | 147 | void unlink_anon_vmas(struct vm_area_struct *); |
| 93 | void anon_vma_unlink(struct vm_area_struct *); | 148 | int anon_vma_clone(struct vm_area_struct *, struct vm_area_struct *); |
| 94 | void anon_vma_link(struct vm_area_struct *); | 149 | int anon_vma_fork(struct vm_area_struct *, struct vm_area_struct *); |
| 95 | void __anon_vma_link(struct vm_area_struct *); | 150 | void __anon_vma_link(struct vm_area_struct *); |
| 96 | void anon_vma_free(struct anon_vma *); | 151 | void anon_vma_free(struct anon_vma *); |
| 97 | 152 | ||
| 153 | static inline void anon_vma_merge(struct vm_area_struct *vma, | ||
| 154 | struct vm_area_struct *next) | ||
| 155 | { | ||
| 156 | VM_BUG_ON(vma->anon_vma != next->anon_vma); | ||
| 157 | unlink_anon_vmas(next); | ||
| 158 | } | ||
| 159 | |||
| 98 | /* | 160 | /* |
| 99 | * rmap interfaces called when adding or removing pte of page | 161 | * rmap interfaces called when adding or removing pte of page |
| 100 | */ | 162 | */ |
| 163 | void page_move_anon_rmap(struct page *, struct vm_area_struct *, unsigned long); | ||
| 101 | void page_add_anon_rmap(struct page *, struct vm_area_struct *, unsigned long); | 164 | void page_add_anon_rmap(struct page *, struct vm_area_struct *, unsigned long); |
| 165 | void do_page_add_anon_rmap(struct page *, struct vm_area_struct *, | ||
| 166 | unsigned long, int); | ||
| 102 | void page_add_new_anon_rmap(struct page *, struct vm_area_struct *, unsigned long); | 167 | void page_add_new_anon_rmap(struct page *, struct vm_area_struct *, unsigned long); |
| 103 | void page_add_file_rmap(struct page *); | 168 | void page_add_file_rmap(struct page *); |
| 104 | void page_remove_rmap(struct page *); | 169 | void page_remove_rmap(struct page *); |
| 105 | 170 | ||
| 171 | void hugepage_add_anon_rmap(struct page *, struct vm_area_struct *, | ||
| 172 | unsigned long); | ||
| 173 | void hugepage_add_new_anon_rmap(struct page *, struct vm_area_struct *, | ||
| 174 | unsigned long); | ||
| 175 | |||
| 106 | static inline void page_dup_rmap(struct page *page) | 176 | static inline void page_dup_rmap(struct page *page) |
| 107 | { | 177 | { |
| 108 | atomic_inc(&page->_mapcount); | 178 | atomic_inc(&page->_mapcount); |
| @@ -181,7 +251,7 @@ static inline int page_referenced(struct page *page, int is_locked, | |||
| 181 | unsigned long *vm_flags) | 251 | unsigned long *vm_flags) |
| 182 | { | 252 | { |
| 183 | *vm_flags = 0; | 253 | *vm_flags = 0; |
| 184 | return TestClearPageReferenced(page); | 254 | return 0; |
| 185 | } | 255 | } |
| 186 | 256 | ||
| 187 | #define try_to_unmap(page, refs) SWAP_FAIL | 257 | #define try_to_unmap(page, refs) SWAP_FAIL |
