diff options
| author | Suraj Das <surajdazz@gmail.com> | 2017-06-25 19:07:06 +0530 |
|---|---|---|
| committer | Suraj Das <surajdazz@gmail.com> | 2017-06-25 19:15:40 +0530 |
| commit | 6e033ebda94e620277a569625745cf21c749efdb (patch) | |
| tree | 641e80dabecde9fd9108b654bf43828d78632509 /mm/migrate.c | |
| parent | fa097959467283e96988ba548a20ccb3ec27c0c1 (diff) | |
| parent | 262196005747d5e8b4106e92adae3749e8686240 (diff) | |
Merge branch 'cm-14.1' of https://github.com/LineageOS/android_kernel_oneplus_msm8974 into n7.1HEADn7.1
Diffstat (limited to 'mm/migrate.c')
| -rw-r--r-- | mm/migrate.c | 48 |
1 files changed, 31 insertions, 17 deletions
diff --git a/mm/migrate.c b/mm/migrate.c index c18e80413e1..73287433c90 100644 --- a/mm/migrate.c +++ b/mm/migrate.c @@ -30,6 +30,7 @@ #include <linux/mempolicy.h> #include <linux/vmalloc.h> #include <linux/security.h> +#include <linux/backing-dev.h> #include <linux/memcontrol.h> #include <linux/syscalls.h> #include <linux/hugetlb.h> @@ -295,6 +296,8 @@ static int migrate_page_move_mapping(struct address_space *mapping, struct page *newpage, struct page *page, struct buffer_head *head, enum migrate_mode mode) { + struct zone *oldzone, *newzone; + int dirty; int expected_count; void **pslot; @@ -305,6 +308,9 @@ static int migrate_page_move_mapping(struct address_space *mapping, return 0; } + oldzone = page_zone(page); + newzone = page_zone(newpage); + spin_lock_irq(&mapping->tree_lock); pslot = radix_tree_lookup_slot(&mapping->page_tree, @@ -345,6 +351,13 @@ static int migrate_page_move_mapping(struct address_space *mapping, set_page_private(newpage, page_private(page)); } + /* Move dirty while page refs frozen and newpage not yet exposed */ + dirty = PageDirty(page); + if (dirty) { + ClearPageDirty(page); + SetPageDirty(newpage); + } + radix_tree_replace_slot(pslot, newpage); /* @@ -354,6 +367,9 @@ static int migrate_page_move_mapping(struct address_space *mapping, */ page_unfreeze_refs(page, expected_count - 1); + spin_unlock(&mapping->tree_lock); + /* Leave irq disabled to prevent preemption while updating stats */ + /* * If moved to a different zone then also account * the page for that zone. Other VM counters will be @@ -364,13 +380,19 @@ static int migrate_page_move_mapping(struct address_space *mapping, * via NR_FILE_PAGES and NR_ANON_PAGES if they * are mapped to swap space. */ - __dec_zone_page_state(page, NR_FILE_PAGES); - __inc_zone_page_state(newpage, NR_FILE_PAGES); - if (!PageSwapCache(page) && PageSwapBacked(page)) { - __dec_zone_page_state(page, NR_SHMEM); - __inc_zone_page_state(newpage, NR_SHMEM); + if (newzone != oldzone) { + __dec_zone_state(oldzone, NR_FILE_PAGES); + __inc_zone_state(newzone, NR_FILE_PAGES); + if (PageSwapBacked(page) && !PageSwapCache(page)) { + __dec_zone_state(oldzone, NR_SHMEM); + __inc_zone_state(newzone, NR_SHMEM); + } + if (dirty && mapping_cap_account_dirty(mapping)) { + __dec_zone_state(oldzone, NR_FILE_DIRTY); + __inc_zone_state(newzone, NR_FILE_DIRTY); + } } - spin_unlock_irq(&mapping->tree_lock); + local_irq_enable(); return 0; } @@ -444,17 +466,9 @@ void migrate_page_copy(struct page *newpage, struct page *page) if (PageMappedToDisk(page)) SetPageMappedToDisk(newpage); - if (PageDirty(page)) { - clear_page_dirty_for_io(page); - /* - * Want to mark the page and the radix tree as dirty, and - * redo the accounting that clear_page_dirty_for_io undid, - * but we can't use set_page_dirty because that function - * is actually a signal that all of the page has become dirty. - * Whereas only part of our page may be dirty. - */ - __set_page_dirty_nobuffers(newpage); - } + /* Move dirty on pages not done by migrate_page_move_mapping() */ + if (PageDirty(page)) + SetPageDirty(newpage); mlock_migrate_page(newpage, page); ksm_migrate_page(newpage, page); |
