aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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;