mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-28 10:41:38 -04:00
memcg: better migration handling
This patch changes page migration under memory controller to use a different algorithm. (thanks to Christoph for new idea.) Before: - page_cgroup is migrated from an old page to a new page. After: - a new page is accounted , no reuse of page_cgroup. Pros: - We can avoid compliated lock depndencies and races in migration. Cons: - new param to mem_cgroup_charge_common(). - mem_cgroup_getref() is added for handling ref_cnt ping-pong. This version simplifies complicated lock dependency in page migraiton under memory resource controller. new refcnt sequence is following. a mapped page: prepage_migration() ..... +1 to NEW page try_to_unmap() ..... all refs to OLD page is gone. move_pages() ..... +1 to NEW page if page cache. remap... ..... all refs from *map* is added to NEW one. end_migration() ..... -1 to New page. page's mapcount + (page_is_cache) refs are added to NEW one. Signed-off-by: KAMEZAWA Hiroyuki <[email protected]> Cc: Balbir Singh <[email protected]> Cc: Pavel Emelyanov <[email protected]> Cc: Li Zefan <[email protected]> Cc: YAMAMOTO Takashi <[email protected]> Cc: Hugh Dickins <[email protected]> Cc: Christoph Lameter <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
This commit is contained in:
parent
508b7be0a5
commit
e8589cc189
3 changed files with 86 additions and 75 deletions
22
mm/migrate.c
22
mm/migrate.c
|
|
@ -358,6 +358,10 @@ static int migrate_page_move_mapping(struct address_space *mapping,
|
|||
__inc_zone_page_state(newpage, NR_FILE_PAGES);
|
||||
|
||||
write_unlock_irq(&mapping->tree_lock);
|
||||
if (!PageSwapCache(newpage)) {
|
||||
mem_cgroup_uncharge_page(page);
|
||||
mem_cgroup_getref(newpage);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -611,7 +615,6 @@ static int move_to_new_page(struct page *newpage, struct page *page)
|
|||
rc = fallback_migrate_page(mapping, newpage, page);
|
||||
|
||||
if (!rc) {
|
||||
mem_cgroup_page_migration(page, newpage);
|
||||
remove_migration_ptes(page, newpage);
|
||||
} else
|
||||
newpage->mapping = NULL;
|
||||
|
|
@ -641,6 +644,14 @@ static int unmap_and_move(new_page_t get_new_page, unsigned long private,
|
|||
/* page was freed from under us. So we are done. */
|
||||
goto move_newpage;
|
||||
|
||||
charge = mem_cgroup_prepare_migration(page, newpage);
|
||||
if (charge == -ENOMEM) {
|
||||
rc = -ENOMEM;
|
||||
goto move_newpage;
|
||||
}
|
||||
/* prepare cgroup just returns 0 or -ENOMEM */
|
||||
BUG_ON(charge);
|
||||
|
||||
rc = -EAGAIN;
|
||||
if (TestSetPageLocked(page)) {
|
||||
if (!force)
|
||||
|
|
@ -692,19 +703,14 @@ static int unmap_and_move(new_page_t get_new_page, unsigned long private,
|
|||
goto rcu_unlock;
|
||||
}
|
||||
|
||||
charge = mem_cgroup_prepare_migration(page);
|
||||
/* Establish migration ptes or remove ptes */
|
||||
try_to_unmap(page, 1);
|
||||
|
||||
if (!page_mapped(page))
|
||||
rc = move_to_new_page(newpage, page);
|
||||
|
||||
if (rc) {
|
||||
if (rc)
|
||||
remove_migration_ptes(page, page);
|
||||
if (charge)
|
||||
mem_cgroup_end_migration(page);
|
||||
} else if (charge)
|
||||
mem_cgroup_end_migration(newpage);
|
||||
rcu_unlock:
|
||||
if (rcu_locked)
|
||||
rcu_read_unlock();
|
||||
|
|
@ -725,6 +731,8 @@ unlock:
|
|||
}
|
||||
|
||||
move_newpage:
|
||||
if (!charge)
|
||||
mem_cgroup_end_migration(newpage);
|
||||
/*
|
||||
* Move the new page to the LRU. If migration was not successful
|
||||
* then this will free the page.
|
||||
|
|
|
|||
Loading…
Reference in a new issue