mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-28 10:41:38 -04:00
bugfix for memory cgroup controller: migration under memory controller fix
While using memory control cgroup, page-migration under it works as following.
==
1. uncharge all refs at try to unmap.
2. charge regs again remove_migration_ptes()
==
This is simple but has following problems.
==
The page is uncharged and charged back again if *mapped*.
- This means that cgroup before migration can be different from one after
migration
- If page is not mapped but charged as page cache, charge is just ignored
(because not mapped, it will not be uncharged before migration)
This is memory leak.
==
This patch tries to keep memory cgroup at page migration by increasing
one refcnt during it. 3 functions are added.
mem_cgroup_prepare_migration() --- increase refcnt of page->page_cgroup
mem_cgroup_end_migration() --- decrease refcnt of page->page_cgroup
mem_cgroup_page_migration() --- copy page->page_cgroup from old page to
new page.
During migration
- old page is under PG_locked.
- new page is under PG_locked, too.
- both old page and new page is not on LRU.
These 3 facts guarantee that page_cgroup() migration has no race.
Tested and worked well in x86_64/fake-NUMA box.
Signed-off-by: KAMEZAWA Hiroyuki <[email protected]>
Cc: Balbir Singh <[email protected]>
Cc: Pavel Emelianov <[email protected]>
Cc: Paul Menage <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: "Eric W. Biederman" <[email protected]>
Cc: Nick Piggin <[email protected]>
Cc: Kirill Korotaev <[email protected]>
Cc: Herbert Poetzl <[email protected]>
Cc: David Rientjes <[email protected]>
Cc: Vaidyanathan Srinivasan <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
This commit is contained in:
parent
9175e0311e
commit
ae41be3742
3 changed files with 72 additions and 3 deletions
13
mm/migrate.c
13
mm/migrate.c
|
|
@ -593,9 +593,10 @@ static int move_to_new_page(struct page *newpage, struct page *page)
|
|||
else
|
||||
rc = fallback_migrate_page(mapping, newpage, page);
|
||||
|
||||
if (!rc)
|
||||
if (!rc) {
|
||||
mem_cgroup_page_migration(page, newpage);
|
||||
remove_migration_ptes(page, newpage);
|
||||
else
|
||||
} else
|
||||
newpage->mapping = NULL;
|
||||
|
||||
unlock_page(newpage);
|
||||
|
|
@ -614,6 +615,7 @@ static int unmap_and_move(new_page_t get_new_page, unsigned long private,
|
|||
int *result = NULL;
|
||||
struct page *newpage = get_new_page(page, private, &result);
|
||||
int rcu_locked = 0;
|
||||
int charge = 0;
|
||||
|
||||
if (!newpage)
|
||||
return -ENOMEM;
|
||||
|
|
@ -673,14 +675,19 @@ 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();
|
||||
|
|
|
|||
Loading…
Reference in a new issue