aboutsummaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
authorHugh Dickins <hughd@google.com>2011-01-13 18:47:30 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2011-01-13 20:32:49 -0500
commit1ce82b69e96c838d007f316b8347b911fdfa9842 (patch)
treebe34e7c88a2544e620638834c8120b14b277d64a /mm
parent2919bfd0758257c469abef8c26c3e516bbebb851 (diff)
mm: fix migration hangs on anon_vma lock
Increased usage of page migration in mmotm reveals that the anon_vma locking in unmap_and_move() has been deficient since 2.6.36 (or even earlier). Review at the time of f18194275c39835cb84563500995e0d503a32d9a ("mm: fix hang on anon_vma->root->lock") missed the issue here: the anon_vma to which we get a reference may already have been freed back to its slab (it is in use when we check page_mapped, but that can change), and so its anon_vma->root may be switched at any moment by reuse in anon_vma_prepare. Perhaps we could fix that with a get_anon_vma_unless_zero(), but let's not: just rely on page_lock_anon_vma() to do all the hard thinking for us, then we don't need any rcu read locking over here. In removing the rcu_unlock label: since PageAnon is a bit in page->mapping, it's impossible for a !page->mapping page to be anon; but insert VM_BUG_ON in case the implementation ever changes. [akpm@linux-foundation.org: coding-style fixes] Signed-off-by: Hugh Dickins <hughd@google.com> Reviewed-by: Mel Gorman <mel@csn.ul.ie> Reviewed-by: Rik van Riel <riel@redhat.com> Cc: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com> Cc: "Jun'ichi Nomura" <j-nomura@ce.jp.nec.com> Cc: Andi Kleen <ak@linux.intel.com> Cc: <stable@kernel.org> [2.6.37, 2.6.36] 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/migrate.c48
1 files changed, 19 insertions, 29 deletions
diff --git a/mm/migrate.c b/mm/migrate.c
index 89a6bc8cd307..a20cf12edede 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -622,7 +622,6 @@ static int unmap_and_move(new_page_t get_new_page, unsigned long private,
622 int *result = NULL; 622 int *result = NULL;
623 struct page *newpage = get_new_page(page, private, &result); 623 struct page *newpage = get_new_page(page, private, &result);
624 int remap_swapcache = 1; 624 int remap_swapcache = 1;
625 int rcu_locked = 0;
626 int charge = 0; 625 int charge = 0;
627 struct mem_cgroup *mem = NULL; 626 struct mem_cgroup *mem = NULL;
628 struct anon_vma *anon_vma = NULL; 627 struct anon_vma *anon_vma = NULL;
@@ -694,20 +693,26 @@ static int unmap_and_move(new_page_t get_new_page, unsigned long private,
694 /* 693 /*
695 * By try_to_unmap(), page->mapcount goes down to 0 here. In this case, 694 * By try_to_unmap(), page->mapcount goes down to 0 here. In this case,
696 * we cannot notice that anon_vma is freed while we migrates a page. 695 * we cannot notice that anon_vma is freed while we migrates a page.
697 * This rcu_read_lock() delays freeing anon_vma pointer until the end 696 * This get_anon_vma() delays freeing anon_vma pointer until the end
698 * of migration. File cache pages are no problem because of page_lock() 697 * of migration. File cache pages are no problem because of page_lock()
699 * File Caches may use write_page() or lock_page() in migration, then, 698 * File Caches may use write_page() or lock_page() in migration, then,
700 * just care Anon page here. 699 * just care Anon page here.
701 */ 700 */
702 if (PageAnon(page)) { 701 if (PageAnon(page)) {
703 rcu_read_lock(); 702 /*
704 rcu_locked = 1; 703 * Only page_lock_anon_vma() understands the subtleties of
705 704 * getting a hold on an anon_vma from outside one of its mms.
706 /* Determine how to safely use anon_vma */ 705 */
707 if (!page_mapped(page)) { 706 anon_vma = page_lock_anon_vma(page);
708 if (!PageSwapCache(page)) 707 if (anon_vma) {
709 goto rcu_unlock; 708 /*
710 709 * Take a reference count on the anon_vma if the
710 * page is mapped so that it is guaranteed to
711 * exist when the page is remapped later
712 */
713 get_anon_vma(anon_vma);
714 page_unlock_anon_vma(anon_vma);
715 } else if (PageSwapCache(page)) {
711 /* 716 /*
712 * We cannot be sure that the anon_vma of an unmapped 717 * We cannot be sure that the anon_vma of an unmapped
713 * swapcache page is safe to use because we don't 718 * swapcache page is safe to use because we don't
@@ -722,13 +727,7 @@ static int unmap_and_move(new_page_t get_new_page, unsigned long private,
722 */ 727 */
723 remap_swapcache = 0; 728 remap_swapcache = 0;
724 } else { 729 } else {
725 /* 730 goto uncharge;
726 * Take a reference count on the anon_vma if the
727 * page is mapped so that it is guaranteed to
728 * exist when the page is remapped later
729 */
730 anon_vma = page_anon_vma(page);
731 get_anon_vma(anon_vma);
732 } 731 }
733 } 732 }
734 733
@@ -745,16 +744,10 @@ static int unmap_and_move(new_page_t get_new_page, unsigned long private,
745 * free the metadata, so the page can be freed. 744 * free the metadata, so the page can be freed.
746 */ 745 */
747 if (!page->mapping) { 746 if (!page->mapping) {
748 if (!PageAnon(page) && page_has_private(page)) { 747 VM_BUG_ON(PageAnon(page));
749 /* 748 if (page_has_private(page)) {
750 * Go direct to try_to_free_buffers() here because
751 * a) that's what try_to_release_page() would do anyway
752 * b) we may be under rcu_read_lock() here, so we can't
753 * use GFP_KERNEL which is what try_to_release_page()
754 * needs to be effective.
755 */
756 try_to_free_buffers(page); 749 try_to_free_buffers(page);
757 goto rcu_unlock; 750 goto uncharge;
758 } 751 }
759 goto skip_unmap; 752 goto skip_unmap;
760 } 753 }
@@ -768,14 +761,11 @@ skip_unmap:
768 761
769 if (rc && remap_swapcache) 762 if (rc && remap_swapcache)
770 remove_migration_ptes(page, page); 763 remove_migration_ptes(page, page);
771rcu_unlock:
772 764
773 /* Drop an anon_vma reference if we took one */ 765 /* Drop an anon_vma reference if we took one */
774 if (anon_vma) 766 if (anon_vma)
775 drop_anon_vma(anon_vma); 767 drop_anon_vma(anon_vma);
776 768
777 if (rcu_locked)
778 rcu_read_unlock();
779uncharge: 769uncharge:
780 if (!charge) 770 if (!charge)
781 mem_cgroup_end_migration(mem, page, newpage); 771 mem_cgroup_end_migration(mem, page, newpage);