diff options
author | Hugh Dickins <hughd@google.com> | 2015-11-05 21:49:53 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-11-05 22:34:48 -0500 |
commit | 5c3f9a67371643b6faa987622bc1b67667bab848 (patch) | |
tree | 6c29472764822d11cd53509a7bc93aa3f6803e1c /mm/migrate.c | |
parent | 7db7671f835ccad66db20154ac1274140937d9b7 (diff) |
mm: page migration remove_migration_ptes at lock+unlock level
Clean up page migration a little more by calling remove_migration_ptes()
from the same level, on success or on failure, from __unmap_and_move() or
from unmap_and_move_huge_page().
Don't reset page->mapping of a PageAnon old page in move_to_new_page(),
leave that to when the page is freed. Except for here in page migration,
it has been an invariant that a PageAnon (bit set in page->mapping) page
stays PageAnon until it is freed, and I think we're safer to keep to that.
And with the above rearrangement, it's necessary because zap_pte_range()
wants to identify whether a migration entry represents a file or an anon
page, to update the appropriate rss stats without waiting on it.
Signed-off-by: Hugh Dickins <hughd@google.com>
Cc: Christoph Lameter <cl@linux.com>
Cc: "Kirill A. Shutemov" <kirill.shutemov@linux.intel.com>
Cc: Rik van Riel <riel@redhat.com>
Cc: Vlastimil Babka <vbabka@suse.cz>
Cc: Davidlohr Bueso <dave@stgolabs.net>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Sasha Levin <sasha.levin@oracle.com>
Cc: Dmitry Vyukov <dvyukov@google.com>
Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm/migrate.c')
-rw-r--r-- | mm/migrate.c | 34 |
1 files changed, 19 insertions, 15 deletions
diff --git a/mm/migrate.c b/mm/migrate.c index 6d7774ef0e6c..7b44ebdf2d26 100644 --- a/mm/migrate.c +++ b/mm/migrate.c | |||
@@ -722,7 +722,7 @@ static int fallback_migrate_page(struct address_space *mapping, | |||
722 | * MIGRATEPAGE_SUCCESS - success | 722 | * MIGRATEPAGE_SUCCESS - success |
723 | */ | 723 | */ |
724 | static int move_to_new_page(struct page *newpage, struct page *page, | 724 | static int move_to_new_page(struct page *newpage, struct page *page, |
725 | int page_was_mapped, enum migrate_mode mode) | 725 | enum migrate_mode mode) |
726 | { | 726 | { |
727 | struct address_space *mapping; | 727 | struct address_space *mapping; |
728 | int rc; | 728 | int rc; |
@@ -755,19 +755,21 @@ static int move_to_new_page(struct page *newpage, struct page *page, | |||
755 | * space which also has its own migratepage callback. This | 755 | * space which also has its own migratepage callback. This |
756 | * is the most common path for page migration. | 756 | * is the most common path for page migration. |
757 | */ | 757 | */ |
758 | rc = mapping->a_ops->migratepage(mapping, | 758 | rc = mapping->a_ops->migratepage(mapping, newpage, page, mode); |
759 | newpage, page, mode); | ||
760 | else | 759 | else |
761 | rc = fallback_migrate_page(mapping, newpage, page, mode); | 760 | rc = fallback_migrate_page(mapping, newpage, page, mode); |
762 | 761 | ||
763 | if (rc != MIGRATEPAGE_SUCCESS) { | 762 | /* |
763 | * When successful, old pagecache page->mapping must be cleared before | ||
764 | * page is freed; but stats require that PageAnon be left as PageAnon. | ||
765 | */ | ||
766 | if (rc == MIGRATEPAGE_SUCCESS) { | ||
767 | set_page_memcg(page, NULL); | ||
768 | if (!PageAnon(page)) | ||
769 | page->mapping = NULL; | ||
770 | } else { | ||
764 | set_page_memcg(newpage, NULL); | 771 | set_page_memcg(newpage, NULL); |
765 | newpage->mapping = NULL; | 772 | newpage->mapping = NULL; |
766 | } else { | ||
767 | set_page_memcg(page, NULL); | ||
768 | if (page_was_mapped) | ||
769 | remove_migration_ptes(page, newpage); | ||
770 | page->mapping = NULL; | ||
771 | } | 773 | } |
772 | return rc; | 774 | return rc; |
773 | } | 775 | } |
@@ -902,10 +904,11 @@ static int __unmap_and_move(struct page *page, struct page *newpage, | |||
902 | } | 904 | } |
903 | 905 | ||
904 | if (!page_mapped(page)) | 906 | if (!page_mapped(page)) |
905 | rc = move_to_new_page(newpage, page, page_was_mapped, mode); | 907 | rc = move_to_new_page(newpage, page, mode); |
906 | 908 | ||
907 | if (rc && page_was_mapped) | 909 | if (page_was_mapped) |
908 | remove_migration_ptes(page, page); | 910 | remove_migration_ptes(page, |
911 | rc == MIGRATEPAGE_SUCCESS ? newpage : page); | ||
909 | 912 | ||
910 | out_unlock_both: | 913 | out_unlock_both: |
911 | unlock_page(newpage); | 914 | unlock_page(newpage); |
@@ -1066,10 +1069,11 @@ static int unmap_and_move_huge_page(new_page_t get_new_page, | |||
1066 | } | 1069 | } |
1067 | 1070 | ||
1068 | if (!page_mapped(hpage)) | 1071 | if (!page_mapped(hpage)) |
1069 | rc = move_to_new_page(new_hpage, hpage, page_was_mapped, mode); | 1072 | rc = move_to_new_page(new_hpage, hpage, mode); |
1070 | 1073 | ||
1071 | if (rc != MIGRATEPAGE_SUCCESS && page_was_mapped) | 1074 | if (page_was_mapped) |
1072 | remove_migration_ptes(hpage, hpage); | 1075 | remove_migration_ptes(hpage, |
1076 | rc == MIGRATEPAGE_SUCCESS ? new_hpage : hpage); | ||
1073 | 1077 | ||
1074 | unlock_page(new_hpage); | 1078 | unlock_page(new_hpage); |
1075 | 1079 | ||