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/memcontrol.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/memcontrol.c')
-rw-r--r-- | mm/memcontrol.c | 43 |
1 files changed, 43 insertions, 0 deletions
diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 3270ce7375db..128f45c16fa6 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c | |||
@@ -492,6 +492,49 @@ void mem_cgroup_uncharge(struct page_cgroup *pc) | |||
492 | } | 492 | } |
493 | } | 493 | } |
494 | } | 494 | } |
495 | /* | ||
496 | * Returns non-zero if a page (under migration) has valid page_cgroup member. | ||
497 | * Refcnt of page_cgroup is incremented. | ||
498 | */ | ||
499 | |||
500 | int mem_cgroup_prepare_migration(struct page *page) | ||
501 | { | ||
502 | struct page_cgroup *pc; | ||
503 | int ret = 0; | ||
504 | lock_page_cgroup(page); | ||
505 | pc = page_get_page_cgroup(page); | ||
506 | if (pc && atomic_inc_not_zero(&pc->ref_cnt)) | ||
507 | ret = 1; | ||
508 | unlock_page_cgroup(page); | ||
509 | return ret; | ||
510 | } | ||
511 | |||
512 | void mem_cgroup_end_migration(struct page *page) | ||
513 | { | ||
514 | struct page_cgroup *pc = page_get_page_cgroup(page); | ||
515 | mem_cgroup_uncharge(pc); | ||
516 | } | ||
517 | /* | ||
518 | * We know both *page* and *newpage* are now not-on-LRU and Pg_locked. | ||
519 | * And no race with uncharge() routines because page_cgroup for *page* | ||
520 | * has extra one reference by mem_cgroup_prepare_migration. | ||
521 | */ | ||
522 | |||
523 | void mem_cgroup_page_migration(struct page *page, struct page *newpage) | ||
524 | { | ||
525 | struct page_cgroup *pc; | ||
526 | retry: | ||
527 | pc = page_get_page_cgroup(page); | ||
528 | if (!pc) | ||
529 | return; | ||
530 | if (clear_page_cgroup(page, pc) != pc) | ||
531 | goto retry; | ||
532 | pc->page = newpage; | ||
533 | lock_page_cgroup(newpage); | ||
534 | page_assign_page_cgroup(newpage, pc); | ||
535 | unlock_page_cgroup(newpage); | ||
536 | return; | ||
537 | } | ||
495 | 538 | ||
496 | int mem_cgroup_write_strategy(char *buf, unsigned long long *tmp) | 539 | int mem_cgroup_write_strategy(char *buf, unsigned long long *tmp) |
497 | { | 540 | { |