diff options
author | Daisuke Nishimura <nishimura@mxp.nes.nec.co.jp> | 2010-03-10 18:22:13 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-03-12 18:52:36 -0500 |
commit | 7dc74be032bfcaa2f9d9e4296ff5bbddfa9e2f19 (patch) | |
tree | 8bd10dcca3cfb3f4f6a0e6222c7f2048995a7d5f /mm/memcontrol.c | |
parent | b70cc5fdb445a6929a01e9c406593265b136c99d (diff) |
memcg: add interface to move charge at task migration
In current memcg, charges associated with a task aren't moved to the new
cgroup at task migration. Some users feel this behavior to be strange.
These patches are for this feature, that is, for charging to the new
cgroup and, of course, uncharging from the old cgroup at task migration.
This patch adds "memory.move_charge_at_immigrate" file, which is a flag
file to determine whether charges should be moved to the new cgroup at
task migration or not and what type of charges should be moved. This
patch also adds read and write handlers of the file.
This patch also adds no-op handlers for this feature. These handlers will
be implemented in later patches. And you cannot write any values other
than 0 to move_charge_at_immigrate yet.
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: 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.c | 97 |
1 files changed, 93 insertions, 4 deletions
diff --git a/mm/memcontrol.c b/mm/memcontrol.c index d813823ab08f..59ffaf511d77 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c | |||
@@ -226,11 +226,26 @@ struct mem_cgroup { | |||
226 | bool memsw_is_minimum; | 226 | bool memsw_is_minimum; |
227 | 227 | ||
228 | /* | 228 | /* |
229 | * Should we move charges of a task when a task is moved into this | ||
230 | * mem_cgroup ? And what type of charges should we move ? | ||
231 | */ | ||
232 | unsigned long move_charge_at_immigrate; | ||
233 | |||
234 | /* | ||
229 | * statistics. This must be placed at the end of memcg. | 235 | * statistics. This must be placed at the end of memcg. |
230 | */ | 236 | */ |
231 | struct mem_cgroup_stat stat; | 237 | struct mem_cgroup_stat stat; |
232 | }; | 238 | }; |
233 | 239 | ||
240 | /* Stuffs for move charges at task migration. */ | ||
241 | /* | ||
242 | * Types of charges to be moved. "move_charge_at_immitgrate" is treated as a | ||
243 | * left-shifted bitmap of these types. | ||
244 | */ | ||
245 | enum move_type { | ||
246 | NR_MOVE_TYPE, | ||
247 | }; | ||
248 | |||
234 | /* | 249 | /* |
235 | * Maximum loops in mem_cgroup_hierarchical_reclaim(), used for soft | 250 | * Maximum loops in mem_cgroup_hierarchical_reclaim(), used for soft |
236 | * limit reclaim to prevent infinite loops, if they ever occur. | 251 | * limit reclaim to prevent infinite loops, if they ever occur. |
@@ -2865,6 +2880,31 @@ static int mem_cgroup_reset(struct cgroup *cont, unsigned int event) | |||
2865 | return 0; | 2880 | return 0; |
2866 | } | 2881 | } |
2867 | 2882 | ||
2883 | static u64 mem_cgroup_move_charge_read(struct cgroup *cgrp, | ||
2884 | struct cftype *cft) | ||
2885 | { | ||
2886 | return mem_cgroup_from_cont(cgrp)->move_charge_at_immigrate; | ||
2887 | } | ||
2888 | |||
2889 | static int mem_cgroup_move_charge_write(struct cgroup *cgrp, | ||
2890 | struct cftype *cft, u64 val) | ||
2891 | { | ||
2892 | struct mem_cgroup *mem = mem_cgroup_from_cont(cgrp); | ||
2893 | |||
2894 | if (val >= (1 << NR_MOVE_TYPE)) | ||
2895 | return -EINVAL; | ||
2896 | /* | ||
2897 | * We check this value several times in both in can_attach() and | ||
2898 | * attach(), so we need cgroup lock to prevent this value from being | ||
2899 | * inconsistent. | ||
2900 | */ | ||
2901 | cgroup_lock(); | ||
2902 | mem->move_charge_at_immigrate = val; | ||
2903 | cgroup_unlock(); | ||
2904 | |||
2905 | return 0; | ||
2906 | } | ||
2907 | |||
2868 | 2908 | ||
2869 | /* For read statistics */ | 2909 | /* For read statistics */ |
2870 | enum { | 2910 | enum { |
@@ -3098,6 +3138,11 @@ static struct cftype mem_cgroup_files[] = { | |||
3098 | .read_u64 = mem_cgroup_swappiness_read, | 3138 | .read_u64 = mem_cgroup_swappiness_read, |
3099 | .write_u64 = mem_cgroup_swappiness_write, | 3139 | .write_u64 = mem_cgroup_swappiness_write, |
3100 | }, | 3140 | }, |
3141 | { | ||
3142 | .name = "move_charge_at_immigrate", | ||
3143 | .read_u64 = mem_cgroup_move_charge_read, | ||
3144 | .write_u64 = mem_cgroup_move_charge_write, | ||
3145 | }, | ||
3101 | }; | 3146 | }; |
3102 | 3147 | ||
3103 | #ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP | 3148 | #ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP |
@@ -3345,6 +3390,7 @@ mem_cgroup_create(struct cgroup_subsys *ss, struct cgroup *cont) | |||
3345 | if (parent) | 3390 | if (parent) |
3346 | mem->swappiness = get_swappiness(parent); | 3391 | mem->swappiness = get_swappiness(parent); |
3347 | atomic_set(&mem->refcnt, 1); | 3392 | atomic_set(&mem->refcnt, 1); |
3393 | mem->move_charge_at_immigrate = 0; | ||
3348 | return &mem->css; | 3394 | return &mem->css; |
3349 | free_out: | 3395 | free_out: |
3350 | __mem_cgroup_free(mem); | 3396 | __mem_cgroup_free(mem); |
@@ -3381,16 +3427,57 @@ static int mem_cgroup_populate(struct cgroup_subsys *ss, | |||
3381 | return ret; | 3427 | return ret; |
3382 | } | 3428 | } |
3383 | 3429 | ||
3430 | /* Handlers for move charge at task migration. */ | ||
3431 | static int mem_cgroup_can_move_charge(void) | ||
3432 | { | ||
3433 | return 0; | ||
3434 | } | ||
3435 | |||
3436 | static int mem_cgroup_can_attach(struct cgroup_subsys *ss, | ||
3437 | struct cgroup *cgroup, | ||
3438 | struct task_struct *p, | ||
3439 | bool threadgroup) | ||
3440 | { | ||
3441 | int ret = 0; | ||
3442 | struct mem_cgroup *mem = mem_cgroup_from_cont(cgroup); | ||
3443 | |||
3444 | if (mem->move_charge_at_immigrate) { | ||
3445 | struct mm_struct *mm; | ||
3446 | struct mem_cgroup *from = mem_cgroup_from_task(p); | ||
3447 | |||
3448 | VM_BUG_ON(from == mem); | ||
3449 | |||
3450 | mm = get_task_mm(p); | ||
3451 | if (!mm) | ||
3452 | return 0; | ||
3453 | |||
3454 | /* We move charges only when we move a owner of the mm */ | ||
3455 | if (mm->owner == p) | ||
3456 | ret = mem_cgroup_can_move_charge(); | ||
3457 | |||
3458 | mmput(mm); | ||
3459 | } | ||
3460 | return ret; | ||
3461 | } | ||
3462 | |||
3463 | static void mem_cgroup_cancel_attach(struct cgroup_subsys *ss, | ||
3464 | struct cgroup *cgroup, | ||
3465 | struct task_struct *p, | ||
3466 | bool threadgroup) | ||
3467 | { | ||
3468 | } | ||
3469 | |||
3470 | static void mem_cgroup_move_charge(void) | ||
3471 | { | ||
3472 | } | ||
3473 | |||
3384 | static void mem_cgroup_move_task(struct cgroup_subsys *ss, | 3474 | static void mem_cgroup_move_task(struct cgroup_subsys *ss, |
3385 | struct cgroup *cont, | 3475 | struct cgroup *cont, |
3386 | struct cgroup *old_cont, | 3476 | struct cgroup *old_cont, |
3387 | struct task_struct *p, | 3477 | struct task_struct *p, |
3388 | bool threadgroup) | 3478 | bool threadgroup) |
3389 | { | 3479 | { |
3390 | /* | 3480 | mem_cgroup_move_charge(); |
3391 | * FIXME: It's better to move charges of this process from old | ||
3392 | * memcg to new memcg. But it's just on TODO-List now. | ||
3393 | */ | ||
3394 | } | 3481 | } |
3395 | 3482 | ||
3396 | struct cgroup_subsys mem_cgroup_subsys = { | 3483 | struct cgroup_subsys mem_cgroup_subsys = { |
@@ -3400,6 +3487,8 @@ struct cgroup_subsys mem_cgroup_subsys = { | |||
3400 | .pre_destroy = mem_cgroup_pre_destroy, | 3487 | .pre_destroy = mem_cgroup_pre_destroy, |
3401 | .destroy = mem_cgroup_destroy, | 3488 | .destroy = mem_cgroup_destroy, |
3402 | .populate = mem_cgroup_populate, | 3489 | .populate = mem_cgroup_populate, |
3490 | .can_attach = mem_cgroup_can_attach, | ||
3491 | .cancel_attach = mem_cgroup_cancel_attach, | ||
3403 | .attach = mem_cgroup_move_task, | 3492 | .attach = mem_cgroup_move_task, |
3404 | .early_init = 0, | 3493 | .early_init = 0, |
3405 | .use_id = 1, | 3494 | .use_id = 1, |