diff options
author | Peter Zijlstra <a.p.zijlstra@chello.nl> | 2011-05-24 20:12:10 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-05-25 11:39:19 -0400 |
commit | 746b18d421da7f27e948e8af1ad82b6d0309324d (patch) | |
tree | d4e756977673b7b8166c00e34a21d85c5e26ea6e /mm/rmap.c | |
parent | 6111e4ca6829a0e8b092b8e5eeb6b5366091f29c (diff) |
mm: use refcounts for page_lock_anon_vma()
Convert page_lock_anon_vma() over to use refcounts. This is done to
prepare for the conversion of anon_vma from spinlock to mutex.
Sadly this inceases the cost of page_lock_anon_vma() from one to two
atomics, a follow up patch addresses this, lets keep that simple for now.
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Reviewed-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Reviewed-by: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Acked-by: Hugh Dickins <hughd@google.com>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: David Miller <davem@davemloft.net>
Cc: Martin Schwidefsky <schwidefsky@de.ibm.com>
Cc: Russell King <rmk@arm.linux.org.uk>
Cc: Paul Mundt <lethal@linux-sh.org>
Cc: Jeff Dike <jdike@addtoit.com>
Cc: Richard Weinberger <richard@nod.at>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Mel Gorman <mel@csn.ul.ie>
Cc: Nick Piggin <npiggin@kernel.dk>
Cc: Namhyung Kim <namhyung@gmail.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 | 42 |
1 files changed, 27 insertions, 15 deletions
@@ -337,9 +337,9 @@ void __init anon_vma_init(void) | |||
337 | * that the anon_vma pointer from page->mapping is valid if there is a | 337 | * that the anon_vma pointer from page->mapping is valid if there is a |
338 | * mapcount, we can dereference the anon_vma after observing those. | 338 | * mapcount, we can dereference the anon_vma after observing those. |
339 | */ | 339 | */ |
340 | struct anon_vma *page_lock_anon_vma(struct page *page) | 340 | struct anon_vma *page_get_anon_vma(struct page *page) |
341 | { | 341 | { |
342 | struct anon_vma *anon_vma, *root_anon_vma; | 342 | struct anon_vma *anon_vma = NULL; |
343 | unsigned long anon_mapping; | 343 | unsigned long anon_mapping; |
344 | 344 | ||
345 | rcu_read_lock(); | 345 | rcu_read_lock(); |
@@ -350,30 +350,42 @@ struct anon_vma *page_lock_anon_vma(struct page *page) | |||
350 | goto out; | 350 | goto out; |
351 | 351 | ||
352 | anon_vma = (struct anon_vma *) (anon_mapping - PAGE_MAPPING_ANON); | 352 | anon_vma = (struct anon_vma *) (anon_mapping - PAGE_MAPPING_ANON); |
353 | root_anon_vma = ACCESS_ONCE(anon_vma->root); | 353 | if (!atomic_inc_not_zero(&anon_vma->refcount)) { |
354 | spin_lock(&root_anon_vma->lock); | 354 | anon_vma = NULL; |
355 | goto out; | ||
356 | } | ||
355 | 357 | ||
356 | /* | 358 | /* |
357 | * If this page is still mapped, then its anon_vma cannot have been | 359 | * If this page is still mapped, then its anon_vma cannot have been |
358 | * freed. But if it has been unmapped, we have no security against | 360 | * freed. But if it has been unmapped, we have no security against the |
359 | * the anon_vma structure being freed and reused (for another anon_vma: | 361 | * anon_vma structure being freed and reused (for another anon_vma: |
360 | * SLAB_DESTROY_BY_RCU guarantees that - so the spin_lock above cannot | 362 | * SLAB_DESTROY_BY_RCU guarantees that - so the atomic_inc_not_zero() |
361 | * corrupt): with anon_vma_prepare() or anon_vma_fork() redirecting | 363 | * above cannot corrupt). |
362 | * anon_vma->root before page_unlock_anon_vma() is called to unlock. | ||
363 | */ | 364 | */ |
364 | if (page_mapped(page)) | 365 | if (!page_mapped(page)) { |
365 | return anon_vma; | 366 | put_anon_vma(anon_vma); |
366 | 367 | anon_vma = NULL; | |
367 | spin_unlock(&root_anon_vma->lock); | 368 | } |
368 | out: | 369 | out: |
369 | rcu_read_unlock(); | 370 | rcu_read_unlock(); |
370 | return NULL; | 371 | |
372 | return anon_vma; | ||
373 | } | ||
374 | |||
375 | struct anon_vma *page_lock_anon_vma(struct page *page) | ||
376 | { | ||
377 | struct anon_vma *anon_vma = page_get_anon_vma(page); | ||
378 | |||
379 | if (anon_vma) | ||
380 | anon_vma_lock(anon_vma); | ||
381 | |||
382 | return anon_vma; | ||
371 | } | 383 | } |
372 | 384 | ||
373 | void page_unlock_anon_vma(struct anon_vma *anon_vma) | 385 | void page_unlock_anon_vma(struct anon_vma *anon_vma) |
374 | { | 386 | { |
375 | anon_vma_unlock(anon_vma); | 387 | anon_vma_unlock(anon_vma); |
376 | rcu_read_unlock(); | 388 | put_anon_vma(anon_vma); |
377 | } | 389 | } |
378 | 390 | ||
379 | /* | 391 | /* |