aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>2009-06-17 19:27:17 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-06-18 16:03:47 -0400
commit8a9478ca7f4bcb8945cec7f95d52dae2d5e50cbd (patch)
tree935e6ee3340ebe999374b54967cc2fa14e8d0060
parent20ebcdda78a282d1d5266887ddf8a2d670182576 (diff)
memcg: fix swap accounting
This patch fixes mis-accounting of swap usage in memcg. In the current implementation, memcg's swap account is uncharged only when swap is completely freed. But there are several cases where swap cannot be freed cleanly. For handling that, this patch changes that memcg uncharges swap account when swap has no references other than cache. By this, memcg's swap entry accounting can be fully synchronous with the application's behavior. This patch also changes memcg's hooks for swap-out. Signed-off-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> Cc: Daisuke Nishimura <nishimura@mxp.nes.nec.co.jp> Acked-by: Balbir Singh <balbir@in.ibm.com> Cc: Hugh Dickins <hugh.dickins@tiscali.co.uk> Cc: Johannes Weiner <hannes@cmpxchg.org> Cc: Li Zefan <lizf@cn.fujitsu.com> Cc: Dhaval Giani <dhaval@linux.vnet.ibm.com> Cc: YAMAMOTO Takashi <yamamoto@valinux.co.jp> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--include/linux/swap.h5
-rw-r--r--mm/memcontrol.c17
-rw-r--r--mm/swapfile.c16
3 files changed, 27 insertions, 11 deletions
diff --git a/include/linux/swap.h b/include/linux/swap.h
index dca9b9999aeb..c88b36665f79 100644
--- a/include/linux/swap.h
+++ b/include/linux/swap.h
@@ -319,10 +319,11 @@ static inline void disable_swap_token(void)
319} 319}
320 320
321#ifdef CONFIG_CGROUP_MEM_RES_CTLR 321#ifdef CONFIG_CGROUP_MEM_RES_CTLR
322extern void mem_cgroup_uncharge_swapcache(struct page *page, swp_entry_t ent); 322extern void
323mem_cgroup_uncharge_swapcache(struct page *page, swp_entry_t ent, bool swapout);
323#else 324#else
324static inline void 325static inline void
325mem_cgroup_uncharge_swapcache(struct page *page, swp_entry_t ent) 326mem_cgroup_uncharge_swapcache(struct page *page, swp_entry_t ent, bool swapout)
326{ 327{
327} 328}
328#endif 329#endif
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 3468c38adde6..a83e0395444b 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -189,6 +189,7 @@ enum charge_type {
189 MEM_CGROUP_CHARGE_TYPE_SHMEM, /* used by page migration of shmem */ 189 MEM_CGROUP_CHARGE_TYPE_SHMEM, /* used by page migration of shmem */
190 MEM_CGROUP_CHARGE_TYPE_FORCE, /* used by force_empty */ 190 MEM_CGROUP_CHARGE_TYPE_FORCE, /* used by force_empty */
191 MEM_CGROUP_CHARGE_TYPE_SWAPOUT, /* for accounting swapcache */ 191 MEM_CGROUP_CHARGE_TYPE_SWAPOUT, /* for accounting swapcache */
192 MEM_CGROUP_CHARGE_TYPE_DROP, /* a page was unused swap cache */
192 NR_CHARGE_TYPE, 193 NR_CHARGE_TYPE,
193}; 194};
194 195
@@ -1493,6 +1494,7 @@ __mem_cgroup_uncharge_common(struct page *page, enum charge_type ctype)
1493 1494
1494 switch (ctype) { 1495 switch (ctype) {
1495 case MEM_CGROUP_CHARGE_TYPE_MAPPED: 1496 case MEM_CGROUP_CHARGE_TYPE_MAPPED:
1497 case MEM_CGROUP_CHARGE_TYPE_DROP:
1496 if (page_mapped(page)) 1498 if (page_mapped(page))
1497 goto unlock_out; 1499 goto unlock_out;
1498 break; 1500 break;
@@ -1556,18 +1558,23 @@ void mem_cgroup_uncharge_cache_page(struct page *page)
1556 * called after __delete_from_swap_cache() and drop "page" account. 1558 * called after __delete_from_swap_cache() and drop "page" account.
1557 * memcg information is recorded to swap_cgroup of "ent" 1559 * memcg information is recorded to swap_cgroup of "ent"
1558 */ 1560 */
1559void mem_cgroup_uncharge_swapcache(struct page *page, swp_entry_t ent) 1561void
1562mem_cgroup_uncharge_swapcache(struct page *page, swp_entry_t ent, bool swapout)
1560{ 1563{
1561 struct mem_cgroup *memcg; 1564 struct mem_cgroup *memcg;
1565 int ctype = MEM_CGROUP_CHARGE_TYPE_SWAPOUT;
1566
1567 if (!swapout) /* this was a swap cache but the swap is unused ! */
1568 ctype = MEM_CGROUP_CHARGE_TYPE_DROP;
1569
1570 memcg = __mem_cgroup_uncharge_common(page, ctype);
1562 1571
1563 memcg = __mem_cgroup_uncharge_common(page,
1564 MEM_CGROUP_CHARGE_TYPE_SWAPOUT);
1565 /* record memcg information */ 1572 /* record memcg information */
1566 if (do_swap_account && memcg) { 1573 if (do_swap_account && swapout && memcg) {
1567 swap_cgroup_record(ent, css_id(&memcg->css)); 1574 swap_cgroup_record(ent, css_id(&memcg->css));
1568 mem_cgroup_get(memcg); 1575 mem_cgroup_get(memcg);
1569 } 1576 }
1570 if (memcg) 1577 if (swapout && memcg)
1571 css_put(&memcg->css); 1578 css_put(&memcg->css);
1572} 1579}
1573#endif 1580#endif
diff --git a/mm/swapfile.c b/mm/swapfile.c
index 28faa01cf578..d1ade1a48ee7 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -583,8 +583,9 @@ static int swap_entry_free(struct swap_info_struct *p,
583 swap_list.next = p - swap_info; 583 swap_list.next = p - swap_info;
584 nr_swap_pages++; 584 nr_swap_pages++;
585 p->inuse_pages--; 585 p->inuse_pages--;
586 mem_cgroup_uncharge_swap(ent);
587 } 586 }
587 if (!swap_count(count))
588 mem_cgroup_uncharge_swap(ent);
588 return count; 589 return count;
589} 590}
590 591
@@ -609,12 +610,19 @@ void swap_free(swp_entry_t entry)
609void swapcache_free(swp_entry_t entry, struct page *page) 610void swapcache_free(swp_entry_t entry, struct page *page)
610{ 611{
611 struct swap_info_struct *p; 612 struct swap_info_struct *p;
613 int ret;
612 614
613 if (page)
614 mem_cgroup_uncharge_swapcache(page, entry);
615 p = swap_info_get(entry); 615 p = swap_info_get(entry);
616 if (p) { 616 if (p) {
617 swap_entry_free(p, entry, SWAP_CACHE); 617 ret = swap_entry_free(p, entry, SWAP_CACHE);
618 if (page) {
619 bool swapout;
620 if (ret)
621 swapout = true; /* the end of swap out */
622 else
623 swapout = false; /* no more swap users! */
624 mem_cgroup_uncharge_swapcache(page, entry, swapout);
625 }
618 spin_unlock(&swap_lock); 626 spin_unlock(&swap_lock);
619 } 627 }
620 return; 628 return;