From d751e53a9cd77b0fa239fc843f838655c47484d8 Mon Sep 17 00:00:00 2001 From: Mel Gorman Date: Mon, 24 May 2010 14:32:20 -0700 Subject: [PATCH] --- yaml --- r: 198240 b: refs/heads/master c: 3fe2011ff51e92500010a495df4be86745fbbda9 h: refs/heads/master v: v3 --- [refs] | 2 +- trunk/mm/migrate.c | 53 +++++++++++++++++++++++++++++++--------------- 2 files changed, 37 insertions(+), 18 deletions(-) diff --git a/[refs] b/[refs] index b715a7820701..48600204c979 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 67b9509b2c68ae38cecb83a239881cb0ddf087dc +refs/heads/master: 3fe2011ff51e92500010a495df4be86745fbbda9 diff --git a/trunk/mm/migrate.c b/trunk/mm/migrate.c index b114635962dc..4afd6fe3c074 100644 --- a/trunk/mm/migrate.c +++ b/trunk/mm/migrate.c @@ -485,7 +485,8 @@ static int fallback_migrate_page(struct address_space *mapping, * < 0 - error code * == 0 - success */ -static int move_to_new_page(struct page *newpage, struct page *page) +static int move_to_new_page(struct page *newpage, struct page *page, + int remap_swapcache) { struct address_space *mapping; int rc; @@ -520,10 +521,12 @@ static int move_to_new_page(struct page *newpage, struct page *page) else rc = fallback_migrate_page(mapping, newpage, page); - if (!rc) - remove_migration_ptes(page, newpage); - else + if (rc) { newpage->mapping = NULL; + } else { + if (remap_swapcache) + remove_migration_ptes(page, newpage); + } unlock_page(newpage); @@ -540,6 +543,7 @@ static int unmap_and_move(new_page_t get_new_page, unsigned long private, int rc = 0; int *result = NULL; struct page *newpage = get_new_page(page, private, &result); + int remap_swapcache = 1; int rcu_locked = 0; int charge = 0; struct mem_cgroup *mem = NULL; @@ -601,18 +605,33 @@ static int unmap_and_move(new_page_t get_new_page, unsigned long private, rcu_read_lock(); rcu_locked = 1; - /* - * If the page has no mappings any more, just bail. An - * unmapped anon page is likely to be freed soon but worse, - * it's possible its anon_vma disappeared between when - * the page was isolated and when we reached here while - * the RCU lock was not held - */ - if (!page_mapped(page)) - goto rcu_unlock; + /* Determine how to safely use anon_vma */ + if (!page_mapped(page)) { + if (!PageSwapCache(page)) + goto rcu_unlock; - anon_vma = page_anon_vma(page); - atomic_inc(&anon_vma->external_refcount); + /* + * We cannot be sure that the anon_vma of an unmapped + * swapcache page is safe to use because we don't + * know in advance if the VMA that this page belonged + * to still exists. If the VMA and others sharing the + * data have been freed, then the anon_vma could + * already be invalid. + * + * To avoid this possibility, swapcache pages get + * migrated but are not remapped when migration + * completes + */ + remap_swapcache = 0; + } else { + /* + * Take a reference count on the anon_vma if the + * page is mapped so that it is guaranteed to + * exist when the page is remapped later + */ + anon_vma = page_anon_vma(page); + atomic_inc(&anon_vma->external_refcount); + } } /* @@ -647,9 +666,9 @@ static int unmap_and_move(new_page_t get_new_page, unsigned long private, skip_unmap: if (!page_mapped(page)) - rc = move_to_new_page(newpage, page); + rc = move_to_new_page(newpage, page, remap_swapcache); - if (rc) + if (rc && remap_swapcache) remove_migration_ptes(page, page); rcu_unlock: