aboutsummaryrefslogtreecommitdiffstats
path: root/include/linux
diff options
context:
space:
mode:
authorKAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>2009-01-07 21:08:00 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2009-01-08 11:31:05 -0500
commit8c7c6e34a1256a5082d38c8e9bd1474476912715 (patch)
tree09f53c7c4bac5532a9ecbdadb4450702c744ea6f /include/linux
parent27a7faa0779dd13729196c1a818c294f44bbd1ee (diff)
memcg: mem+swap controller core
This patch implements per cgroup limit for usage of memory+swap. However there are SwapCache, double counting of swap-cache and swap-entry is avoided. Mem+Swap controller works as following. - memory usage is limited by memory.limit_in_bytes. - memory + swap usage is limited by memory.memsw_limit_in_bytes. This has following benefits. - A user can limit total resource usage of mem+swap. Without this, because memory resource controller doesn't take care of usage of swap, a process can exhaust all the swap (by memory leak.) We can avoid this case. And Swap is shared resource but it cannot be reclaimed (goes back to memory) until it's used. This characteristic can be trouble when the memory is divided into some parts by cpuset or memcg. Assume group A and group B. After some application executes, the system can be.. Group A -- very large free memory space but occupy 99% of swap. Group B -- under memory shortage but cannot use swap...it's nearly full. Ability to set appropriate swap limit for each group is required. Maybe someone wonder "why not swap but mem+swap ?" - The global LRU(kswapd) can swap out arbitrary pages. Swap-out means to move account from memory to swap...there is no change in usage of mem+swap. In other words, when we want to limit the usage of swap without affecting global LRU, mem+swap limit is better than just limiting swap. Accounting target information is stored in swap_cgroup which is per swap entry record. Charge is done as following. map - charge page and memsw. unmap - uncharge page/memsw if not SwapCache. swap-out (__delete_from_swap_cache) - uncharge page - record mem_cgroup information to swap_cgroup. swap-in (do_swap_page) - charged as page and memsw. record in swap_cgroup is cleared. memsw accounting is decremented. swap-free (swap_free()) - if swap entry is freed, memsw is uncharged by PAGE_SIZE. There are people work under never-swap environments and consider swap as something bad. For such people, this mem+swap controller extension is just an overhead. This overhead is avoided by config or boot option. (see Kconfig. detail is not in this patch.) TODO: - maybe more optimization can be don in swap-in path. (but not very safe.) But we just do simple accounting at this stage. [nishimura@mxp.nes.nec.co.jp: make resize limit hold mutex] [hugh@veritas.com: memswap controller core swapcache fixes] 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: Pavel Emelyanov <xemul@openvz.org> Signed-off-by: Daisuke Nishimura <nishimura@mxp.nes.nec.co.jp> Signed-off-by: Hugh Dickins <hugh@veritas.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'include/linux')
-rw-r--r--include/linux/memcontrol.h11
-rw-r--r--include/linux/swap.h14
2 files changed, 20 insertions, 5 deletions
diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h
index 41b46cc9d1f1..ca51ac72d6c0 100644
--- a/include/linux/memcontrol.h
+++ b/include/linux/memcontrol.h
@@ -32,6 +32,8 @@ extern int mem_cgroup_newpage_charge(struct page *page, struct mm_struct *mm,
32/* for swap handling */ 32/* for swap handling */
33extern int mem_cgroup_try_charge(struct mm_struct *mm, 33extern int mem_cgroup_try_charge(struct mm_struct *mm,
34 gfp_t gfp_mask, struct mem_cgroup **ptr); 34 gfp_t gfp_mask, struct mem_cgroup **ptr);
35extern int mem_cgroup_try_charge_swapin(struct mm_struct *mm,
36 struct page *page, gfp_t mask, struct mem_cgroup **ptr);
35extern void mem_cgroup_commit_charge_swapin(struct page *page, 37extern void mem_cgroup_commit_charge_swapin(struct page *page,
36 struct mem_cgroup *ptr); 38 struct mem_cgroup *ptr);
37extern void mem_cgroup_cancel_charge_swapin(struct mem_cgroup *ptr); 39extern void mem_cgroup_cancel_charge_swapin(struct mem_cgroup *ptr);
@@ -80,7 +82,6 @@ extern long mem_cgroup_calc_reclaim(struct mem_cgroup *mem, struct zone *zone,
80#ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP 82#ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP
81extern int do_swap_account; 83extern int do_swap_account;
82#endif 84#endif
83
84#else /* CONFIG_CGROUP_MEM_RES_CTLR */ 85#else /* CONFIG_CGROUP_MEM_RES_CTLR */
85struct mem_cgroup; 86struct mem_cgroup;
86 87
@@ -97,7 +98,13 @@ static inline int mem_cgroup_cache_charge(struct page *page,
97} 98}
98 99
99static inline int mem_cgroup_try_charge(struct mm_struct *mm, 100static inline int mem_cgroup_try_charge(struct mm_struct *mm,
100 gfp_t gfp_mask, struct mem_cgroup **ptr) 101 gfp_t gfp_mask, struct mem_cgroup **ptr)
102{
103 return 0;
104}
105
106static inline int mem_cgroup_try_charge_swapin(struct mm_struct *mm,
107 struct page *page, gfp_t gfp_mask, struct mem_cgroup **ptr)
101{ 108{
102 return 0; 109 return 0;
103} 110}
diff --git a/include/linux/swap.h b/include/linux/swap.h
index f8f3907533f0..be938ce4895a 100644
--- a/include/linux/swap.h
+++ b/include/linux/swap.h
@@ -214,7 +214,7 @@ static inline void lru_cache_add_active_file(struct page *page)
214extern unsigned long try_to_free_pages(struct zonelist *zonelist, int order, 214extern unsigned long try_to_free_pages(struct zonelist *zonelist, int order,
215 gfp_t gfp_mask); 215 gfp_t gfp_mask);
216extern unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *mem, 216extern unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *mem,
217 gfp_t gfp_mask); 217 gfp_t gfp_mask, bool noswap);
218extern int __isolate_lru_page(struct page *page, int mode, int file); 218extern int __isolate_lru_page(struct page *page, int mode, int file);
219extern unsigned long shrink_all_memory(unsigned long nr_pages); 219extern unsigned long shrink_all_memory(unsigned long nr_pages);
220extern int vm_swappiness; 220extern int vm_swappiness;
@@ -336,7 +336,7 @@ static inline void disable_swap_token(void)
336#ifdef CONFIG_CGROUP_MEM_RES_CTLR 336#ifdef CONFIG_CGROUP_MEM_RES_CTLR
337extern int mem_cgroup_cache_charge_swapin(struct page *page, 337extern int mem_cgroup_cache_charge_swapin(struct page *page,
338 struct mm_struct *mm, gfp_t mask, bool locked); 338 struct mm_struct *mm, gfp_t mask, bool locked);
339extern void mem_cgroup_uncharge_swapcache(struct page *page); 339extern void mem_cgroup_uncharge_swapcache(struct page *page, swp_entry_t ent);
340#else 340#else
341static inline 341static inline
342int mem_cgroup_cache_charge_swapin(struct page *page, 342int mem_cgroup_cache_charge_swapin(struct page *page,
@@ -344,7 +344,15 @@ int mem_cgroup_cache_charge_swapin(struct page *page,
344{ 344{
345 return 0; 345 return 0;
346} 346}
347static inline void mem_cgroup_uncharge_swapcache(struct page *page) 347static inline void
348mem_cgroup_uncharge_swapcache(struct page *page, swp_entry_t ent)
349{
350}
351#endif
352#ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP
353extern void mem_cgroup_uncharge_swap(swp_entry_t ent);
354#else
355static inline void mem_cgroup_uncharge_swap(swp_entry_t ent)
348{ 356{
349} 357}
350#endif 358#endif