aboutsummaryrefslogtreecommitdiffstats
path: root/mm/memcontrol.c
diff options
context:
space:
mode:
authorKAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>2009-04-02 19:57:45 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-04-02 22:04:56 -0400
commita3b2d692690aef228e493b1beaafe5364cab3237 (patch)
treed3ad99c5370462861a1b918b4136e7bd7ad78e52 /mm/memcontrol.c
parent3c776e64660028236313f0e54f3a9945764422df (diff)
cgroups: use css id in swap cgroup for saving memory v5
Try to use CSS ID for records in swap_cgroup. By this, on 64bit machine, size of swap_cgroup goes down to 2 bytes from 8bytes. This means, when 2GB of swap is equipped, (assume the page size is 4096bytes) From size of swap_cgroup = 2G/4k * 8 = 4Mbytes. To size of swap_cgroup = 2G/4k * 2 = 1Mbytes. Reduction is large. Of course, there are trade-offs. This CSS ID will add overhead to swap-in/swap-out/swap-free. But in general, - swap is a resource which the user tend to avoid use. - If swap is never used, swap_cgroup area is not used. - Reading traditional manuals, size of swap should be proportional to size of memory. Memory size of machine is increasing now. I think reducing size of swap_cgroup makes sense. Note: - ID->CSS lookup routine has no locks, it's under RCU-Read-Side. - memcg can be obsolete at rmdir() but not freed while refcnt from swap_cgroup is available. Changelog v4->v5: - reworked on to memcg-charge-swapcache-to-proper-memcg.patch Changlog ->v4: - fixed not configured case. - deleted unnecessary comments. - fixed NULL pointer bug. - fixed message in dmesg. [nishimura@mxp.nes.nec.co.jp: css_tryget can be called twice in !PageCgroupUsed case] Signed-off-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> Cc: Li Zefan <lizf@cn.fujitsu.com> Cc: Balbir Singh <balbir@in.ibm.com> Cc: Paul Menage <menage@google.com> Cc: Hugh Dickins <hugh@veritas.com> Signed-off-by: Daisuke Nishimura <nishimura@mxp.nes.nec.co.jp> 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.c74
1 files changed, 62 insertions, 12 deletions
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 81b0ae8183d0..55dea5968464 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -991,10 +991,31 @@ nomem:
991 return -ENOMEM; 991 return -ENOMEM;
992} 992}
993 993
994
995/*
996 * A helper function to get mem_cgroup from ID. must be called under
997 * rcu_read_lock(). The caller must check css_is_removed() or some if
998 * it's concern. (dropping refcnt from swap can be called against removed
999 * memcg.)
1000 */
1001static struct mem_cgroup *mem_cgroup_lookup(unsigned short id)
1002{
1003 struct cgroup_subsys_state *css;
1004
1005 /* ID 0 is unused ID */
1006 if (!id)
1007 return NULL;
1008 css = css_lookup(&mem_cgroup_subsys, id);
1009 if (!css)
1010 return NULL;
1011 return container_of(css, struct mem_cgroup, css);
1012}
1013
994static struct mem_cgroup *try_get_mem_cgroup_from_swapcache(struct page *page) 1014static struct mem_cgroup *try_get_mem_cgroup_from_swapcache(struct page *page)
995{ 1015{
996 struct mem_cgroup *mem; 1016 struct mem_cgroup *mem;
997 struct page_cgroup *pc; 1017 struct page_cgroup *pc;
1018 unsigned short id;
998 swp_entry_t ent; 1019 swp_entry_t ent;
999 1020
1000 VM_BUG_ON(!PageLocked(page)); 1021 VM_BUG_ON(!PageLocked(page));
@@ -1006,16 +1027,19 @@ static struct mem_cgroup *try_get_mem_cgroup_from_swapcache(struct page *page)
1006 /* 1027 /*
1007 * Used bit of swapcache is solid under page lock. 1028 * Used bit of swapcache is solid under page lock.
1008 */ 1029 */
1009 if (PageCgroupUsed(pc)) 1030 if (PageCgroupUsed(pc)) {
1010 mem = pc->mem_cgroup; 1031 mem = pc->mem_cgroup;
1011 else { 1032 if (mem && !css_tryget(&mem->css))
1033 mem = NULL;
1034 } else {
1012 ent.val = page_private(page); 1035 ent.val = page_private(page);
1013 mem = lookup_swap_cgroup(ent); 1036 id = lookup_swap_cgroup(ent);
1037 rcu_read_lock();
1038 mem = mem_cgroup_lookup(id);
1039 if (mem && !css_tryget(&mem->css))
1040 mem = NULL;
1041 rcu_read_unlock();
1014 } 1042 }
1015 if (!mem)
1016 return NULL;
1017 if (!css_tryget(&mem->css))
1018 return NULL;
1019 return mem; 1043 return mem;
1020} 1044}
1021 1045
@@ -1276,12 +1300,22 @@ int mem_cgroup_cache_charge(struct page *page, struct mm_struct *mm,
1276 1300
1277 if (do_swap_account && !ret && PageSwapCache(page)) { 1301 if (do_swap_account && !ret && PageSwapCache(page)) {
1278 swp_entry_t ent = {.val = page_private(page)}; 1302 swp_entry_t ent = {.val = page_private(page)};
1303 unsigned short id;
1279 /* avoid double counting */ 1304 /* avoid double counting */
1280 mem = swap_cgroup_record(ent, NULL); 1305 id = swap_cgroup_record(ent, 0);
1306 rcu_read_lock();
1307 mem = mem_cgroup_lookup(id);
1281 if (mem) { 1308 if (mem) {
1309 /*
1310 * We did swap-in. Then, this entry is doubly counted
1311 * both in mem and memsw. We uncharge it, here.
1312 * Recorded ID can be obsolete. We avoid calling
1313 * css_tryget()
1314 */
1282 res_counter_uncharge(&mem->memsw, PAGE_SIZE); 1315 res_counter_uncharge(&mem->memsw, PAGE_SIZE);
1283 mem_cgroup_put(mem); 1316 mem_cgroup_put(mem);
1284 } 1317 }
1318 rcu_read_unlock();
1285 } 1319 }
1286 return ret; 1320 return ret;
1287} 1321}
@@ -1346,13 +1380,21 @@ void mem_cgroup_commit_charge_swapin(struct page *page, struct mem_cgroup *ptr)
1346 */ 1380 */
1347 if (do_swap_account && PageSwapCache(page)) { 1381 if (do_swap_account && PageSwapCache(page)) {
1348 swp_entry_t ent = {.val = page_private(page)}; 1382 swp_entry_t ent = {.val = page_private(page)};
1383 unsigned short id;
1349 struct mem_cgroup *memcg; 1384 struct mem_cgroup *memcg;
1350 memcg = swap_cgroup_record(ent, NULL); 1385
1386 id = swap_cgroup_record(ent, 0);
1387 rcu_read_lock();
1388 memcg = mem_cgroup_lookup(id);
1351 if (memcg) { 1389 if (memcg) {
1390 /*
1391 * This recorded memcg can be obsolete one. So, avoid
1392 * calling css_tryget
1393 */
1352 res_counter_uncharge(&memcg->memsw, PAGE_SIZE); 1394 res_counter_uncharge(&memcg->memsw, PAGE_SIZE);
1353 mem_cgroup_put(memcg); 1395 mem_cgroup_put(memcg);
1354 } 1396 }
1355 1397 rcu_read_unlock();
1356 } 1398 }
1357 /* add this page(page_cgroup) to the LRU we want. */ 1399 /* add this page(page_cgroup) to the LRU we want. */
1358 1400
@@ -1473,7 +1515,7 @@ void mem_cgroup_uncharge_swapcache(struct page *page, swp_entry_t ent)
1473 MEM_CGROUP_CHARGE_TYPE_SWAPOUT); 1515 MEM_CGROUP_CHARGE_TYPE_SWAPOUT);
1474 /* record memcg information */ 1516 /* record memcg information */
1475 if (do_swap_account && memcg) { 1517 if (do_swap_account && memcg) {
1476 swap_cgroup_record(ent, memcg); 1518 swap_cgroup_record(ent, css_id(&memcg->css));
1477 mem_cgroup_get(memcg); 1519 mem_cgroup_get(memcg);
1478 } 1520 }
1479 if (memcg) 1521 if (memcg)
@@ -1488,15 +1530,23 @@ void mem_cgroup_uncharge_swapcache(struct page *page, swp_entry_t ent)
1488void mem_cgroup_uncharge_swap(swp_entry_t ent) 1530void mem_cgroup_uncharge_swap(swp_entry_t ent)
1489{ 1531{
1490 struct mem_cgroup *memcg; 1532 struct mem_cgroup *memcg;
1533 unsigned short id;
1491 1534
1492 if (!do_swap_account) 1535 if (!do_swap_account)
1493 return; 1536 return;
1494 1537
1495 memcg = swap_cgroup_record(ent, NULL); 1538 id = swap_cgroup_record(ent, 0);
1539 rcu_read_lock();
1540 memcg = mem_cgroup_lookup(id);
1496 if (memcg) { 1541 if (memcg) {
1542 /*
1543 * We uncharge this because swap is freed.
1544 * This memcg can be obsolete one. We avoid calling css_tryget
1545 */
1497 res_counter_uncharge(&memcg->memsw, PAGE_SIZE); 1546 res_counter_uncharge(&memcg->memsw, PAGE_SIZE);
1498 mem_cgroup_put(memcg); 1547 mem_cgroup_put(memcg);
1499 } 1548 }
1549 rcu_read_unlock();
1500} 1550}
1501#endif 1551#endif
1502 1552