diff options
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, |