aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaisuke Nishimura <nishimura@mxp.nes.nec.co.jp>2010-03-10 18:22:17 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2010-03-12 18:52:36 -0500
commit024914477e15ef8b17f271ec47f1bb8a589f0806 (patch)
tree9a6a8b4224c94fcdd1b8c3127b301ee3537f8cc2
parent8033b97c9b5ef063e3f4bf2efe1cd0a22093aaff (diff)
memcg: move charges of anonymous swap
This patch is another core part of this move-charge-at-task-migration feature. It enables moving charges of anonymous swaps. To move the charge of swap, we need to exchange swap_cgroup's record. In current implementation, swap_cgroup's record is protected by: - page lock: if the entry is on swap cache. - swap_lock: if the entry is not on swap cache. This works well in usual swap-in/out activity. But this behavior make the feature of moving swap charge check many conditions to exchange swap_cgroup's record safely. So I changed modification of swap_cgroup's recored(swap_cgroup_record()) to use xchg, and define a new function to cmpxchg swap_cgroup's record. This patch also enables moving charge of non pte_present but not uncharged swap caches, which can be exist on swap-out path, by getting the target pages via find_get_page() as do_mincore() does. [kosaki.motohiro@jp.fujitsu.com: fix ia64 build] [akpm@linux-foundation.org: fix typos] Signed-off-by: Daisuke Nishimura <nishimura@mxp.nes.nec.co.jp> Cc: Balbir Singh <balbir@linux.vnet.ibm.com> Acked-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> Cc: Li Zefan <lizf@cn.fujitsu.com> Cc: Paul Menage <menage@google.com> Cc: Daisuke Nishimura <nishimura@mxp.nes.nec.co.jp> Signed-off-by: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--Documentation/cgroups/memory.txt2
-rw-r--r--include/linux/page_cgroup.h2
-rw-r--r--include/linux/swap.h9
-rw-r--r--mm/memcontrol.c183
-rw-r--r--mm/page_cgroup.c34
-rw-r--r--mm/swapfile.c31
6 files changed, 223 insertions, 38 deletions
diff --git a/Documentation/cgroups/memory.txt b/Documentation/cgroups/memory.txt
index e726fb0df719..1f59a1a38bd9 100644
--- a/Documentation/cgroups/memory.txt
+++ b/Documentation/cgroups/memory.txt
@@ -420,6 +420,8 @@ NOTE2: It is recommended to set the soft limit always below the hard limit,
420 420
421Users can move charges associated with a task along with task migration, that 421Users can move charges associated with a task along with task migration, that
422is, uncharge task's pages from the old cgroup and charge them to the new cgroup. 422is, uncharge task's pages from the old cgroup and charge them to the new cgroup.
423This feature is not supported in !CONFIG_MMU environments because of lack of
424page tables.
423 425
4248.1 Interface 4268.1 Interface
425 427
diff --git a/include/linux/page_cgroup.h b/include/linux/page_cgroup.h
index b0e4eb126236..30b08136fdf3 100644
--- a/include/linux/page_cgroup.h
+++ b/include/linux/page_cgroup.h
@@ -118,6 +118,8 @@ static inline void __init page_cgroup_init_flatmem(void)
118#include <linux/swap.h> 118#include <linux/swap.h>
119 119
120#ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP 120#ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP
121extern unsigned short swap_cgroup_cmpxchg(swp_entry_t ent,
122 unsigned short old, unsigned short new);
121extern unsigned short swap_cgroup_record(swp_entry_t ent, unsigned short id); 123extern unsigned short swap_cgroup_record(swp_entry_t ent, unsigned short id);
122extern unsigned short lookup_swap_cgroup(swp_entry_t ent); 124extern unsigned short lookup_swap_cgroup(swp_entry_t ent);
123extern int swap_cgroup_swapon(int type, unsigned long max_pages); 125extern int swap_cgroup_swapon(int type, unsigned long max_pages);
diff --git a/include/linux/swap.h b/include/linux/swap.h
index a2602a8207a6..1f59d9340c4d 100644
--- a/include/linux/swap.h
+++ b/include/linux/swap.h
@@ -355,6 +355,7 @@ static inline void disable_swap_token(void)
355#ifdef CONFIG_CGROUP_MEM_RES_CTLR 355#ifdef CONFIG_CGROUP_MEM_RES_CTLR
356extern void 356extern void
357mem_cgroup_uncharge_swapcache(struct page *page, swp_entry_t ent, bool swapout); 357mem_cgroup_uncharge_swapcache(struct page *page, swp_entry_t ent, bool swapout);
358extern int mem_cgroup_count_swap_user(swp_entry_t ent, struct page **pagep);
358#else 359#else
359static inline void 360static inline void
360mem_cgroup_uncharge_swapcache(struct page *page, swp_entry_t ent, bool swapout) 361mem_cgroup_uncharge_swapcache(struct page *page, swp_entry_t ent, bool swapout)
@@ -485,6 +486,14 @@ mem_cgroup_uncharge_swapcache(struct page *page, swp_entry_t ent)
485{ 486{
486} 487}
487 488
489#ifdef CONFIG_CGROUP_MEM_RES_CTLR
490static inline int
491mem_cgroup_count_swap_user(swp_entry_t ent, struct page **pagep)
492{
493 return 0;
494}
495#endif
496
488#endif /* CONFIG_SWAP */ 497#endif /* CONFIG_SWAP */
489#endif /* __KERNEL__*/ 498#endif /* __KERNEL__*/
490#endif /* _LINUX_SWAP_H */ 499#endif /* _LINUX_SWAP_H */
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 589084f00b70..e883198baf81 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -33,6 +33,7 @@
33#include <linux/rbtree.h> 33#include <linux/rbtree.h>
34#include <linux/slab.h> 34#include <linux/slab.h>
35#include <linux/swap.h> 35#include <linux/swap.h>
36#include <linux/swapops.h>
36#include <linux/spinlock.h> 37#include <linux/spinlock.h>
37#include <linux/fs.h> 38#include <linux/fs.h>
38#include <linux/seq_file.h> 39#include <linux/seq_file.h>
@@ -2270,6 +2271,54 @@ void mem_cgroup_uncharge_swap(swp_entry_t ent)
2270 } 2271 }
2271 rcu_read_unlock(); 2272 rcu_read_unlock();
2272} 2273}
2274
2275/**
2276 * mem_cgroup_move_swap_account - move swap charge and swap_cgroup's record.
2277 * @entry: swap entry to be moved
2278 * @from: mem_cgroup which the entry is moved from
2279 * @to: mem_cgroup which the entry is moved to
2280 *
2281 * It succeeds only when the swap_cgroup's record for this entry is the same
2282 * as the mem_cgroup's id of @from.
2283 *
2284 * Returns 0 on success, -EINVAL on failure.
2285 *
2286 * The caller must have charged to @to, IOW, called res_counter_charge() about
2287 * both res and memsw, and called css_get().
2288 */
2289static int mem_cgroup_move_swap_account(swp_entry_t entry,
2290 struct mem_cgroup *from, struct mem_cgroup *to)
2291{
2292 unsigned short old_id, new_id;
2293
2294 old_id = css_id(&from->css);
2295 new_id = css_id(&to->css);
2296
2297 if (swap_cgroup_cmpxchg(entry, old_id, new_id) == old_id) {
2298 if (!mem_cgroup_is_root(from))
2299 res_counter_uncharge(&from->memsw, PAGE_SIZE);
2300 mem_cgroup_swap_statistics(from, false);
2301 mem_cgroup_put(from);
2302 /*
2303 * we charged both to->res and to->memsw, so we should uncharge
2304 * to->res.
2305 */
2306 if (!mem_cgroup_is_root(to))
2307 res_counter_uncharge(&to->res, PAGE_SIZE);
2308 mem_cgroup_swap_statistics(to, true);
2309 mem_cgroup_get(to);
2310 css_put(&to->css);
2311
2312 return 0;
2313 }
2314 return -EINVAL;
2315}
2316#else
2317static inline int mem_cgroup_move_swap_account(swp_entry_t entry,
2318 struct mem_cgroup *from, struct mem_cgroup *to)
2319{
2320 return -EINVAL;
2321}
2273#endif 2322#endif
2274 2323
2275/* 2324/*
@@ -2949,6 +2998,7 @@ static u64 mem_cgroup_move_charge_read(struct cgroup *cgrp,
2949 return mem_cgroup_from_cont(cgrp)->move_charge_at_immigrate; 2998 return mem_cgroup_from_cont(cgrp)->move_charge_at_immigrate;
2950} 2999}
2951 3000
3001#ifdef CONFIG_MMU
2952static int mem_cgroup_move_charge_write(struct cgroup *cgrp, 3002static int mem_cgroup_move_charge_write(struct cgroup *cgrp,
2953 struct cftype *cft, u64 val) 3003 struct cftype *cft, u64 val)
2954{ 3004{
@@ -2967,6 +3017,13 @@ static int mem_cgroup_move_charge_write(struct cgroup *cgrp,
2967 3017
2968 return 0; 3018 return 0;
2969} 3019}
3020#else
3021static int mem_cgroup_move_charge_write(struct cgroup *cgrp,
3022 struct cftype *cft, u64 val)
3023{
3024 return -ENOSYS;
3025}
3026#endif
2970 3027
2971 3028
2972/* For read statistics */ 3029/* For read statistics */
@@ -3489,6 +3546,7 @@ static int mem_cgroup_populate(struct cgroup_subsys *ss,
3489 return ret; 3546 return ret;
3490} 3547}
3491 3548
3549#ifdef CONFIG_MMU
3492/* Handlers for move charge at task migration. */ 3550/* Handlers for move charge at task migration. */
3493#define PRECHARGE_COUNT_AT_ONCE 256 3551#define PRECHARGE_COUNT_AT_ONCE 256
3494static int mem_cgroup_do_precharge(unsigned long count) 3552static int mem_cgroup_do_precharge(unsigned long count)
@@ -3544,77 +3602,124 @@ one_by_one:
3544 } 3602 }
3545 return ret; 3603 return ret;
3546} 3604}
3605#else /* !CONFIG_MMU */
3606static int mem_cgroup_can_attach(struct cgroup_subsys *ss,
3607 struct cgroup *cgroup,
3608 struct task_struct *p,
3609 bool threadgroup)
3610{
3611 return 0;
3612}
3613static void mem_cgroup_cancel_attach(struct cgroup_subsys *ss,
3614 struct cgroup *cgroup,
3615 struct task_struct *p,
3616 bool threadgroup)
3617{
3618}
3619static void mem_cgroup_move_task(struct cgroup_subsys *ss,
3620 struct cgroup *cont,
3621 struct cgroup *old_cont,
3622 struct task_struct *p,
3623 bool threadgroup)
3624{
3625}
3626#endif