diff options
-rw-r--r-- | include/linux/rmap.h | 11 | ||||
-rw-r--r-- | mm/rmap.c | 76 |
2 files changed, 37 insertions, 50 deletions
diff --git a/include/linux/rmap.h b/include/linux/rmap.h index fd56111a52c1..830e65dc01ee 100644 --- a/include/linux/rmap.h +++ b/include/linux/rmap.h | |||
@@ -73,7 +73,13 @@ static inline void get_anon_vma(struct anon_vma *anon_vma) | |||
73 | atomic_inc(&anon_vma->refcount); | 73 | atomic_inc(&anon_vma->refcount); |
74 | } | 74 | } |
75 | 75 | ||
76 | void put_anon_vma(struct anon_vma *); | 76 | void __put_anon_vma(struct anon_vma *anon_vma); |
77 | |||
78 | static inline void put_anon_vma(struct anon_vma *anon_vma) | ||
79 | { | ||
80 | if (atomic_dec_and_test(&anon_vma->refcount)) | ||
81 | __put_anon_vma(anon_vma); | ||
82 | } | ||
77 | 83 | ||
78 | static inline struct anon_vma *page_anon_vma(struct page *page) | 84 | static inline struct anon_vma *page_anon_vma(struct page *page) |
79 | { | 85 | { |
@@ -116,7 +122,6 @@ void unlink_anon_vmas(struct vm_area_struct *); | |||
116 | int anon_vma_clone(struct vm_area_struct *, struct vm_area_struct *); | 122 | int anon_vma_clone(struct vm_area_struct *, struct vm_area_struct *); |
117 | int anon_vma_fork(struct vm_area_struct *, struct vm_area_struct *); | 123 | int anon_vma_fork(struct vm_area_struct *, struct vm_area_struct *); |
118 | void __anon_vma_link(struct vm_area_struct *); | 124 | void __anon_vma_link(struct vm_area_struct *); |
119 | void anon_vma_free(struct anon_vma *); | ||
120 | 125 | ||
121 | static inline void anon_vma_merge(struct vm_area_struct *vma, | 126 | static inline void anon_vma_merge(struct vm_area_struct *vma, |
122 | struct vm_area_struct *next) | 127 | struct vm_area_struct *next) |
@@ -125,6 +130,8 @@ static inline void anon_vma_merge(struct vm_area_struct *vma, | |||
125 | unlink_anon_vmas(next); | 130 | unlink_anon_vmas(next); |
126 | } | 131 | } |
127 | 132 | ||
133 | struct anon_vma *page_get_anon_vma(struct page *page); | ||
134 | |||
128 | /* | 135 | /* |
129 | * rmap interfaces called when adding or removing pte of page | 136 | * rmap interfaces called when adding or removing pte of page |
130 | */ | 137 | */ |
@@ -67,11 +67,24 @@ static struct kmem_cache *anon_vma_chain_cachep; | |||
67 | 67 | ||
68 | static inline struct anon_vma *anon_vma_alloc(void) | 68 | static inline struct anon_vma *anon_vma_alloc(void) |
69 | { | 69 | { |
70 | return kmem_cache_alloc(anon_vma_cachep, GFP_KERNEL); | 70 | struct anon_vma *anon_vma; |
71 | |||
72 | anon_vma = kmem_cache_alloc(anon_vma_cachep, GFP_KERNEL); | ||
73 | if (anon_vma) { | ||
74 | atomic_set(&anon_vma->refcount, 1); | ||
75 | /* | ||
76 | * Initialise the anon_vma root to point to itself. If called | ||
77 | * from fork, the root will be reset to the parents anon_vma. | ||
78 | */ | ||
79 | anon_vma->root = anon_vma; | ||
80 | } | ||
81 | |||
82 | return anon_vma; | ||
71 | } | 83 | } |
72 | 84 | ||
73 | void anon_vma_free(struct anon_vma *anon_vma) | 85 | static inline void anon_vma_free(struct anon_vma *anon_vma) |
74 | { | 86 | { |
87 | VM_BUG_ON(atomic_read(&anon_vma->refcount)); | ||
75 | kmem_cache_free(anon_vma_cachep, anon_vma); | 88 | kmem_cache_free(anon_vma_cachep, anon_vma); |
76 | } | 89 | } |
77 | 90 | ||
@@ -133,11 +146,6 @@ int anon_vma_prepare(struct vm_area_struct *vma) | |||
133 | if (unlikely(!anon_vma)) | 146 | if (unlikely(!anon_vma)) |
134 | goto out_enomem_free_avc; | 147 | goto out_enomem_free_avc; |
135 | allocated = anon_vma; | 148 | allocated = anon_vma; |
136 | /* | ||
137 | * This VMA had no anon_vma yet. This anon_vma is | ||
138 | * the root of any anon_vma tree that might form. | ||
139 | */ | ||
140 | anon_vma->root = anon_vma; | ||
141 | } | 149 | } |
142 | 150 | ||
143 | anon_vma_lock(anon_vma); | 151 | anon_vma_lock(anon_vma); |
@@ -156,7 +164,7 @@ int anon_vma_prepare(struct vm_area_struct *vma) | |||
156 | anon_vma_unlock(anon_vma); | 164 | anon_vma_unlock(anon_vma); |
157 | 165 | ||
158 | if (unlikely(allocated)) | 166 | if (unlikely(allocated)) |
159 | anon_vma_free(allocated); | 167 | put_anon_vma(allocated); |
160 | if (unlikely(avc)) | 168 | if (unlikely(avc)) |
161 | anon_vma_chain_free(avc); | 169 | anon_vma_chain_free(avc); |
162 | } | 170 | } |
@@ -241,9 +249,9 @@ int anon_vma_fork(struct vm_area_struct *vma, struct vm_area_struct *pvma) | |||
241 | */ | 249 | */ |
242 | anon_vma->root = pvma->anon_vma->root; | 250 | anon_vma->root = pvma->anon_vma->root; |
243 | /* | 251 | /* |
244 | * With KSM refcounts, an anon_vma can stay around longer than the | 252 | * With refcounts, an anon_vma can stay around longer than the |
245 | * process it belongs to. The root anon_vma needs to be pinned | 253 | * process it belongs to. The root anon_vma needs to be pinned until |
246 | * until this anon_vma is freed, because the lock lives in the root. | 254 | * this anon_vma is freed, because the lock lives in the root. |
247 | */ | 255 | */ |
248 | get_anon_vma(anon_vma->root); | 256 | get_anon_vma(anon_vma->root); |
249 | /* Mark this anon_vma as the one where our new (COWed) pages go. */ | 257 | /* Mark this anon_vma as the one where our new (COWed) pages go. */ |
@@ -253,7 +261,7 @@ int anon_vma_fork(struct vm_area_struct *vma, struct vm_area_struct *pvma) | |||
253 | return 0; | 261 | return 0; |
254 | 262 | ||
255 | out_error_free_anon_vma: | 263 | out_error_free_anon_vma: |
256 | anon_vma_free(anon_vma); | 264 | put_anon_vma(anon_vma); |
257 | out_error: | 265 | out_error: |
258 | unlink_anon_vmas(vma); | 266 | unlink_anon_vmas(vma); |
259 | return -ENOMEM; | 267 | return -ENOMEM; |
@@ -272,15 +280,11 @@ static void anon_vma_unlink(struct anon_vma_chain *anon_vma_chain) | |||
272 | list_del(&anon_vma_chain->same_anon_vma); | 280 | list_del(&anon_vma_chain->same_anon_vma); |
273 | 281 | ||
274 | /* We must garbage collect the anon_vma if it's empty */ | 282 | /* We must garbage collect the anon_vma if it's empty */ |
275 | empty = list_empty(&anon_vma->head) && !atomic_read(&anon_vma->refcount); | 283 | empty = list_empty(&anon_vma->head); |
276 | anon_vma_unlock(anon_vma); | 284 | anon_vma_unlock(anon_vma); |
277 | 285 | ||
278 | if (empty) { | 286 | if (empty) |
279 | /* We no longer need the root anon_vma */ | 287 | put_anon_vma(anon_vma); |
280 | if (anon_vma->root != anon_vma) | ||
281 | put_anon_vma(anon_vma->root); | ||
282 | anon_vma_free(anon_vma); | ||
283 | } | ||
284 | } | 288 | } |
285 | 289 | ||
286 | void unlink_anon_vmas(struct vm_area_struct *vma) | 290 | void unlink_anon_vmas(struct vm_area_struct *vma) |
@@ -1486,38 +1490,14 @@ int try_to_munlock(struct page *page) | |||
1486 | return try_to_unmap_file(page, TTU_MUNLOCK); | 1490 | return try_to_unmap_file(page, TTU_MUNLOCK); |
1487 | } | 1491 | } |
1488 | 1492 | ||
1489 | /* | 1493 | void __put_anon_vma(struct anon_vma *anon_vma) |
1490 | * Drop an anon_vma refcount, freeing the anon_vma and anon_vma->root | ||
1491 | * if necessary. Be careful to do all the tests under the lock. Once | ||
1492 | * we know we are the last user, nobody else can get a reference and we | ||
1493 | * can do the freeing without the lock. | ||
1494 | */ | ||
1495 | void put_anon_vma(struct anon_vma *anon_vma) | ||
1496 | { | 1494 | { |
1497 | BUG_ON(atomic_read(&anon_vma->refcount) <= 0); | 1495 | struct anon_vma *root = anon_vma->root; |
1498 | if (atomic_dec_and_lock(&anon_vma->refcount, &anon_vma->root->lock)) { | ||
1499 | struct anon_vma *root = anon_vma->root; | ||
1500 | int empty = list_empty(&anon_vma->head); | ||
1501 | int last_root_user = 0; | ||
1502 | int root_empty = 0; | ||
1503 | 1496 | ||
1504 | /* | 1497 | if (root != anon_vma && atomic_dec_and_test(&root->refcount)) |
1505 | * The refcount on a non-root anon_vma got dropped. Drop | 1498 | anon_vma_free(root); |
1506 | * the refcount on the root and check if we need to free it. | ||
1507 | */ | ||
1508 | if (empty && anon_vma != root) { | ||
1509 | BUG_ON(atomic_read(&root->refcount) <= 0); | ||
1510 | last_root_user = atomic_dec_and_test(&root->refcount); | ||
1511 | root_empty = list_empty(&root->head); | ||
1512 | } | ||
1513 | anon_vma_unlock(anon_vma); | ||
1514 | 1499 | ||
1515 | if (empty) { | 1500 | anon_vma_free(anon_vma); |
1516 | anon_vma_free(anon_vma); | ||
1517 | if (root_empty && last_root_user) | ||
1518 | anon_vma_free(root); | ||
1519 | } | ||
1520 | } | ||
1521 | } | 1501 | } |
1522 | 1502 | ||
1523 | #ifdef CONFIG_MIGRATION | 1503 | #ifdef CONFIG_MIGRATION |