aboutsummaryrefslogtreecommitdiffstats
path: root/mm/memcontrol.c
diff options
context:
space:
mode:
authorJohannes Weiner <hannes@cmpxchg.org>2016-03-15 17:57:19 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-03-15 19:55:16 -0400
commit6a93ca8fde3cfce0f00f02281139a377c83e8d8c (patch)
tree63846308d4ab27360afdb31330cb8dbf4251cbfe /mm/memcontrol.c
parent23047a96d7cfcfca1a6d026ecaec526ea4803e9e (diff)
mm: migrate: do not touch page->mem_cgroup of live pages
Changing a page's memcg association complicates dealing with the page, so we want to limit this as much as possible. Page migration e.g. does not have to do that. Just like page cache replacement, it can forcibly charge a replacement page, and then uncharge the old page when it gets freed. Temporarily overcharging the cgroup by a single page is not an issue in practice, and charging is so cheap nowadays that this is much preferrable to the headache of messing with live pages. The only place that still changes the page->mem_cgroup binding of live pages is when pages move along with a task to another cgroup. But that path isolates the page from the LRU, takes the page lock, and the move lock (lock_page_memcg()). That means page->mem_cgroup is always stable in callers that have the page isolated from the LRU or locked. Lighter unlocked paths, like writeback accounting, can use lock_page_memcg(). [akpm@linux-foundation.org: fix build] [vdavydov@virtuozzo.com: fix lockdep splat] Signed-off-by: Johannes Weiner <hannes@cmpxchg.org> Acked-by: Vladimir Davydov <vdavydov@virtuozzo.com> Cc: Johannes Weiner <hannes@cmpxchg.org> Cc: Michal Hocko <mhocko@suse.cz> Cc: Greg Thelen <gthelen@google.com> Cc: Hugh Dickins <hughd@google.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.c13
1 files changed, 7 insertions, 6 deletions
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 864e237f32d9..64506b2eef34 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -4457,7 +4457,7 @@ static int mem_cgroup_move_account(struct page *page,
4457 VM_BUG_ON(compound && !PageTransHuge(page)); 4457 VM_BUG_ON(compound && !PageTransHuge(page));
4458 4458
4459 /* 4459 /*
4460 * Prevent mem_cgroup_replace_page() from looking at 4460 * Prevent mem_cgroup_migrate() from looking at
4461 * page->mem_cgroup of its source page while we change it. 4461 * page->mem_cgroup of its source page while we change it.
4462 */ 4462 */
4463 ret = -EBUSY; 4463 ret = -EBUSY;
@@ -5486,16 +5486,17 @@ void mem_cgroup_uncharge_list(struct list_head *page_list)
5486} 5486}
5487 5487
5488/** 5488/**
5489 * mem_cgroup_replace_page - migrate a charge to another page 5489 * mem_cgroup_migrate - charge a page's replacement
5490 * @oldpage: currently charged page 5490 * @oldpage: currently circulating page
5491 * @newpage: page to transfer the charge to 5491 * @newpage: replacement page
5492 * 5492 *
5493 * Migrate the charge from @oldpage to @newpage. 5493 * Charge @newpage as a replacement page for @oldpage. @oldpage will
5494 * be uncharged upon free.
5494 * 5495 *
5495 * Both pages must be locked, @newpage->mapping must be set up. 5496 * Both pages must be locked, @newpage->mapping must be set up.
5496 * Either or both pages might be on the LRU already. 5497 * Either or both pages might be on the LRU already.
5497 */ 5498 */
5498void mem_cgroup_replace_page(struct page *oldpage, struct page *newpage) 5499void mem_cgroup_migrate(struct page *oldpage, struct page *newpage)
5499{ 5500{
5500 struct mem_cgroup *memcg; 5501 struct mem_cgroup *memcg;
5501 unsigned int nr_pages; 5502 unsigned int nr_pages;