diff options
author | KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> | 2008-02-07 03:14:10 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2008-02-07 11:42:19 -0500 |
commit | ae41be374293e70e1ed441d986afcc6e744ef9d9 (patch) | |
tree | d8e2143820bbf3ed2f1f79ed99ee430284567b93 /mm/migrate.c | |
parent | 9175e0311ec9e6d1bf1f6dfecf9268baf08765e6 (diff) |
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 <kamezawa.hiroyu@jp.fujitsu.com>
Cc: Balbir Singh <balbir@linux.vnet.ibm.com>
Cc: Pavel Emelianov <xemul@openvz.org>
Cc: Paul Menage <menage@google.com>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: "Eric W. Biederman" <ebiederm@xmission.com>
Cc: Nick Piggin <nickpiggin@yahoo.com.au>
Cc: Kirill Korotaev <dev@sw.ru>
Cc: Herbert Poetzl <herbert@13thfloor.at>
Cc: David Rientjes <rientjes@google.com>
Cc: Vaidyanathan Srinivasan <svaidy@linux.vnet.ibm.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 | 13 |
1 files changed, 10 insertions, 3 deletions
diff --git a/mm/migrate.c b/mm/migrate.c index 76379414469..a73504ff5ab 100644 --- a/mm/migrate.c +++ b/mm/migrate.c | |||
@@ -593,9 +593,10 @@ static int move_to_new_page(struct page *newpage, struct page *page) | |||
593 | else | 593 | else |
594 | rc = fallback_migrate_page(mapping, newpage, page); | 594 | rc = fallback_migrate_page(mapping, newpage, page); |
595 | 595 | ||
596 | if (!rc) | 596 | if (!rc) { |
597 | mem_cgroup_page_migration(page, newpage); | ||
597 | remove_migration_ptes(page, newpage); | 598 | remove_migration_ptes(page, newpage); |
598 | else | 599 | } else |
599 | newpage->mapping = NULL; | 600 | newpage->mapping = NULL; |
600 | 601 | ||
601 | unlock_page(newpage); | 602 | unlock_page(newpage); |
@@ -614,6 +615,7 @@ static int unmap_and_move(new_page_t get_new_page, unsigned long private, | |||
614 | int *result = NULL; | 615 | int *result = NULL; |
615 | struct page *newpage = get_new_page(page, private, &result); | 616 | struct page *newpage = get_new_page(page, private, &result); |
616 | int rcu_locked = 0; | 617 | int rcu_locked = 0; |
618 | int charge = 0; | ||
617 | 619 | ||
618 | if (!newpage) | 620 | if (!newpage) |
619 | return -ENOMEM; | 621 | return -ENOMEM; |
@@ -673,14 +675,19 @@ static int unmap_and_move(new_page_t get_new_page, unsigned long private, | |||
673 | goto rcu_unlock; | 675 | goto rcu_unlock; |
674 | } | 676 | } |
675 | 677 | ||
678 | charge = mem_cgroup_prepare_migration(page); | ||
676 | /* Establish migration ptes or remove ptes */ | 679 | /* Establish migration ptes or remove ptes */ |
677 | try_to_unmap(page, 1); | 680 | try_to_unmap(page, 1); |
678 | 681 | ||
679 | if (!page_mapped(page)) | 682 | if (!page_mapped(page)) |
680 | rc = move_to_new_page(newpage, page); | 683 | rc = move_to_new_page(newpage, page); |
681 | 684 | ||
682 | if (rc) | 685 | if (rc) { |
683 | remove_migration_ptes(page, page); | 686 | remove_migration_ptes(page, page); |
687 | if (charge) | ||
688 | mem_cgroup_end_migration(page); | ||
689 | } else if (charge) | ||
690 | mem_cgroup_end_migration(newpage); | ||
684 | rcu_unlock: | 691 | rcu_unlock: |
685 | if (rcu_locked) | 692 | if (rcu_locked) |
686 | rcu_read_unlock(); | 693 | rcu_read_unlock(); |