diff options
author | KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> | 2008-07-25 04:47:10 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-07-25 13:53:37 -0400 |
commit | e8589cc189f96b87348ae83ea4db38eaac624135 (patch) | |
tree | 6693422dc81e6da78c4ad892b0d326fb7f946dda /mm/migrate.c | |
parent | 508b7be0a5b06b64203512ed9b34191cddc83f56 (diff) |
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 <kamezawa.hiroyu@jp.fujitsu.com>
Cc: Balbir Singh <balbir@in.ibm.com>
Cc: Pavel Emelyanov <xemul@openvz.org>
Cc: Li Zefan <lizf@cn.fujitsu.com>
Cc: YAMAMOTO Takashi <yamamoto@valinux.co.jp>
Cc: Hugh Dickins <hugh@veritas.com>
Cc: Christoph Lameter <cl@linux-foundation.org>
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 | 22 |
1 files changed, 15 insertions, 7 deletions
diff --git a/mm/migrate.c b/mm/migrate.c index 376cceba82f9..f6d7f8efd1a8 100644 --- a/mm/migrate.c +++ b/mm/migrate.c | |||
@@ -358,6 +358,10 @@ static int migrate_page_move_mapping(struct address_space *mapping, | |||
358 | __inc_zone_page_state(newpage, NR_FILE_PAGES); | 358 | __inc_zone_page_state(newpage, NR_FILE_PAGES); |
359 | 359 | ||
360 | write_unlock_irq(&mapping->tree_lock); | 360 | write_unlock_irq(&mapping->tree_lock); |
361 | if (!PageSwapCache(newpage)) { | ||
362 | mem_cgroup_uncharge_page(page); | ||
363 | mem_cgroup_getref(newpage); | ||
364 | } | ||
361 | 365 | ||
362 | return 0; | 366 | return 0; |
363 | } | 367 | } |
@@ -611,7 +615,6 @@ static int move_to_new_page(struct page *newpage, struct page *page) | |||
611 | rc = fallback_migrate_page(mapping, newpage, page); | 615 | rc = fallback_migrate_page(mapping, newpage, page); |
612 | 616 | ||
613 | if (!rc) { | 617 | if (!rc) { |
614 | mem_cgroup_page_migration(page, newpage); | ||
615 | remove_migration_ptes(page, newpage); | 618 | remove_migration_ptes(page, newpage); |
616 | } else | 619 | } else |
617 | newpage->mapping = NULL; | 620 | newpage->mapping = NULL; |
@@ -641,6 +644,14 @@ static int unmap_and_move(new_page_t get_new_page, unsigned long private, | |||
641 | /* page was freed from under us. So we are done. */ | 644 | /* page was freed from under us. So we are done. */ |
642 | goto move_newpage; | 645 | goto move_newpage; |
643 | 646 | ||
647 | charge = mem_cgroup_prepare_migration(page, newpage); | ||
648 | if (charge == -ENOMEM) { | ||
649 | rc = -ENOMEM; | ||
650 | goto move_newpage; | ||
651 | } | ||
652 | /* prepare cgroup just returns 0 or -ENOMEM */ | ||
653 | BUG_ON(charge); | ||
654 | |||
644 | rc = -EAGAIN; | 655 | rc = -EAGAIN; |
645 | if (TestSetPageLocked(page)) { | 656 | if (TestSetPageLocked(page)) { |
646 | if (!force) | 657 | if (!force) |
@@ -692,19 +703,14 @@ static int unmap_and_move(new_page_t get_new_page, unsigned long private, | |||
692 | goto rcu_unlock; | 703 | goto rcu_unlock; |
693 | } | 704 | } |
694 | 705 | ||
695 | charge = mem_cgroup_prepare_migration(page); | ||
696 | /* Establish migration ptes or remove ptes */ | 706 | /* Establish migration ptes or remove ptes */ |
697 | try_to_unmap(page, 1); | 707 | try_to_unmap(page, 1); |
698 | 708 | ||
699 | if (!page_mapped(page)) | 709 | if (!page_mapped(page)) |
700 | rc = move_to_new_page(newpage, page); | 710 | rc = move_to_new_page(newpage, page); |
701 | 711 | ||
702 | if (rc) { | 712 | if (rc) |
703 | remove_migration_ptes(page, page); | 713 | remove_migration_ptes(page, page); |
704 | if (charge) | ||
705 | mem_cgroup_end_migration(page); | ||
706 | } else if (charge) | ||
707 | mem_cgroup_end_migration(newpage); | ||
708 | rcu_unlock: | 714 | rcu_unlock: |
709 | if (rcu_locked) | 715 | if (rcu_locked) |
710 | rcu_read_unlock(); | 716 | rcu_read_unlock(); |
@@ -725,6 +731,8 @@ unlock: | |||
725 | } | 731 | } |
726 | 732 | ||
727 | move_newpage: | 733 | move_newpage: |
734 | if (!charge) | ||
735 | mem_cgroup_end_migration(newpage); | ||
728 | /* | 736 | /* |
729 | * Move the new page to the LRU. If migration was not successful | 737 | * Move the new page to the LRU. If migration was not successful |
730 | * then this will free the page. | 738 | * then this will free the page. |