aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaisuke Nishimura <nishimura@mxp.nes.nec.co.jp>2009-04-02 19:57:43 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-04-02 22:04:56 -0400
commit3c776e64660028236313f0e54f3a9945764422df (patch)
tree4268ca55283e572ab0e6570cd05030d64048af34
parent3918b96e03b2b8dd05889320623f6870e81d35ec (diff)
memcg: charge swapcache to proper memcg
memcg_test.txt says at 4.1: This swap-in is one of the most complicated work. In do_swap_page(), following events occur when pte is unchanged. (1) the page (SwapCache) is looked up. (2) lock_page() (3) try_charge_swapin() (4) reuse_swap_page() (may call delete_swap_cache()) (5) commit_charge_swapin() (6) swap_free(). Considering following situation for example. (A) The page has not been charged before (2) and reuse_swap_page() doesn't call delete_from_swap_cache(). (B) The page has not been charged before (2) and reuse_swap_page() calls delete_from_swap_cache(). (C) The page has been charged before (2) and reuse_swap_page() doesn't call delete_from_swap_cache(). (D) The page has been charged before (2) and reuse_swap_page() calls delete_from_swap_cache(). memory.usage/memsw.usage changes to this page/swp_entry will be Case (A) (B) (C) (D) Event Before (2) 0/ 1 0/ 1 1/ 1 1/ 1 =========================================== (3) +1/+1 +1/+1 +1/+1 +1/+1 (4) - 0/ 0 - -1/ 0 (5) 0/-1 0/ 0 -1/-1 0/ 0 (6) - 0/-1 - 0/-1 =========================================== Result 1/ 1 1/ 1 1/ 1 1/ 1 In any cases, charges to this page should be 1/ 1. In case of (D), mem_cgroup_try_get_from_swapcache() returns NULL (because lookup_swap_cgroup() returns NULL), so "+1/+1" at (3) means charges to the memcg("foo") to which the "current" belongs. OTOH, "-1/0" at (4) and "0/-1" at (6) means uncharges from the memcg("baa") to which the page has been charged. So, if the "foo" and "baa" is different(for example because of task move), this charge will be moved from "baa" to "foo". I think this is an unexpected behavior. This patch fixes this by modifying mem_cgroup_try_get_from_swapcache() to return the memcg to which the swapcache has been charged if PCG_USED bit is set. IIUC, checking PCG_USED bit of swapcache is safe under page lock. Signed-off-by: Daisuke Nishimura <nishimura@mxp.nes.nec.co.jp> Cc: Balbir Singh <balbir@linux.vnet.ibm.com> Cc: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> Cc: Li Zefan <lizf@cn.fujitsu.com> Cc: Hugh Dickins <hugh@veritas.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--mm/memcontrol.c15
1 files changed, 13 insertions, 2 deletions
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 7bb14fdc780c..81b0ae8183d0 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -994,13 +994,24 @@ nomem:
994static struct mem_cgroup *try_get_mem_cgroup_from_swapcache(struct page *page) 994static struct mem_cgroup *try_get_mem_cgroup_from_swapcache(struct page *page)
995{ 995{
996 struct mem_cgroup *mem; 996 struct mem_cgroup *mem;
997 struct page_cgroup *pc;
997 swp_entry_t ent; 998 swp_entry_t ent;
998 999
1000 VM_BUG_ON(!PageLocked(page));
1001
999 if (!PageSwapCache(page)) 1002 if (!PageSwapCache(page))
1000 return NULL; 1003 return NULL;
1001 1004
1002 ent.val = page_private(page); 1005 pc = lookup_page_cgroup(page);
1003 mem = lookup_swap_cgroup(ent); 1006 /*
1007 * Used bit of swapcache is solid under page lock.
1008 */
1009 if (PageCgroupUsed(pc))
1010 mem = pc->mem_cgroup;
1011 else {
1012 ent.val = page_private(page);
1013 mem = lookup_swap_cgroup(ent);
1014 }
1004 if (!mem) 1015 if (!mem)
1005 return NULL; 1016 return NULL;
1006 if (!css_tryget(&mem->css)) 1017 if (!css_tryget(&mem->css))