aboutsummaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
authorPeter Zijlstra <a.p.zijlstra@chello.nl>2011-03-22 19:32:49 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2011-03-22 20:44:03 -0400
commit01d8b20dec5f4019283e244aba50ba86fe6ead6e (patch)
tree738a2e675547de61f74d6f4019dd5830c40446dd /mm
parent83813267c699ab11cc65a6d9d0f42db42f0862b3 (diff)
mm: simplify anon_vma refcounts
This patch changes the anon_vma refcount to be 0 when the object is free. It does this by adding 1 ref to being in use in the anon_vma structure (iow. the anon_vma->head list is not empty). This allows a simpler release scheme without having to check both the refcount and the list as well as avoids taking a ref for each entry on the list. Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl> Reviewed-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> Acked-by: Hugh Dickins <hughd@google.com> Acked-by: Mel Gorman <mel@csn.ul.ie> Acked-by: Rik van Riel <riel@redhat.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm')
-rw-r--r--mm/rmap.c76
1 files changed, 28 insertions, 48 deletions
diff --git a/mm/rmap.c b/mm/rmap.c
index 873cd9ef912c..4a8e99a0fb97 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -67,11 +67,24 @@ static struct kmem_cache *anon_vma_chain_cachep;
67 67
68static inline struct anon_vma *anon_vma_alloc(void) 68static 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
73void anon_vma_free(struct anon_vma *anon_vma) 85static 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
286void unlink_anon_vmas(struct vm_area_struct *vma) 290void 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/* 1493void __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 */
1495void 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