diff options
| -rw-r--r-- | include/linux/memcontrol.h | 6 | ||||
| -rw-r--r-- | include/linux/swap.h | 8 | ||||
| -rw-r--r-- | mm/memcontrol.c | 16 | ||||
| -rw-r--r-- | mm/thrash.c | 87 | ||||
| -rw-r--r-- | mm/vmscan.c | 4 |
5 files changed, 85 insertions, 36 deletions
diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h index 9724a38ee69..50940da6adf 100644 --- a/include/linux/memcontrol.h +++ b/include/linux/memcontrol.h | |||
| @@ -84,6 +84,7 @@ int task_in_mem_cgroup(struct task_struct *task, const struct mem_cgroup *mem); | |||
| 84 | 84 | ||
| 85 | extern struct mem_cgroup *try_get_mem_cgroup_from_page(struct page *page); | 85 | extern struct mem_cgroup *try_get_mem_cgroup_from_page(struct page *page); |
| 86 | extern struct mem_cgroup *mem_cgroup_from_task(struct task_struct *p); | 86 | extern struct mem_cgroup *mem_cgroup_from_task(struct task_struct *p); |
| 87 | extern struct mem_cgroup *try_get_mem_cgroup_from_mm(struct mm_struct *mm); | ||
| 87 | 88 | ||
| 88 | static inline | 89 | static inline |
| 89 | int mm_match_cgroup(const struct mm_struct *mm, const struct mem_cgroup *cgroup) | 90 | int mm_match_cgroup(const struct mm_struct *mm, const struct mem_cgroup *cgroup) |
| @@ -246,6 +247,11 @@ static inline struct mem_cgroup *try_get_mem_cgroup_from_page(struct page *page) | |||
| 246 | return NULL; | 247 | return NULL; |
| 247 | } | 248 | } |
| 248 | 249 | ||
| 250 | static inline struct mem_cgroup *try_get_mem_cgroup_from_mm(struct mm_struct *mm) | ||
| 251 | { | ||
| 252 | return NULL; | ||
| 253 | } | ||
| 254 | |||
| 249 | static inline int mm_match_cgroup(struct mm_struct *mm, struct mem_cgroup *mem) | 255 | static inline int mm_match_cgroup(struct mm_struct *mm, struct mem_cgroup *mem) |
| 250 | { | 256 | { |
| 251 | return 1; | 257 | return 1; |
diff --git a/include/linux/swap.h b/include/linux/swap.h index 384eb5fe530..e7056464703 100644 --- a/include/linux/swap.h +++ b/include/linux/swap.h | |||
| @@ -358,6 +358,7 @@ struct backing_dev_info; | |||
| 358 | extern struct mm_struct *swap_token_mm; | 358 | extern struct mm_struct *swap_token_mm; |
| 359 | extern void grab_swap_token(struct mm_struct *); | 359 | extern void grab_swap_token(struct mm_struct *); |
| 360 | extern void __put_swap_token(struct mm_struct *); | 360 | extern void __put_swap_token(struct mm_struct *); |
| 361 | extern void disable_swap_token(struct mem_cgroup *memcg); | ||
| 361 | 362 | ||
| 362 | static inline int has_swap_token(struct mm_struct *mm) | 363 | static inline int has_swap_token(struct mm_struct *mm) |
| 363 | { | 364 | { |
| @@ -370,11 +371,6 @@ static inline void put_swap_token(struct mm_struct *mm) | |||
| 370 | __put_swap_token(mm); | 371 | __put_swap_token(mm); |
| 371 | } | 372 | } |
| 372 | 373 | ||
| 373 | static inline void disable_swap_token(void) | ||
| 374 | { | ||
| 375 | put_swap_token(swap_token_mm); | ||
| 376 | } | ||
| 377 | |||
| 378 | #ifdef CONFIG_CGROUP_MEM_RES_CTLR | 374 | #ifdef CONFIG_CGROUP_MEM_RES_CTLR |
| 379 | extern void | 375 | extern void |
| 380 | mem_cgroup_uncharge_swapcache(struct page *page, swp_entry_t ent, bool swapout); | 376 | mem_cgroup_uncharge_swapcache(struct page *page, swp_entry_t ent, bool swapout); |
| @@ -500,7 +496,7 @@ static inline int has_swap_token(struct mm_struct *mm) | |||
| 500 | return 0; | 496 | return 0; |
| 501 | } | 497 | } |
| 502 | 498 | ||
| 503 | static inline void disable_swap_token(void) | 499 | static inline void disable_swap_token(struct mem_cgroup *memcg) |
| 504 | { | 500 | { |
| 505 | } | 501 | } |
| 506 | 502 | ||
diff --git a/mm/memcontrol.c b/mm/memcontrol.c index bd9052a5d3a..e37c44d88d4 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c | |||
| @@ -735,7 +735,7 @@ struct mem_cgroup *mem_cgroup_from_task(struct task_struct *p) | |||
| 735 | struct mem_cgroup, css); | 735 | struct mem_cgroup, css); |
| 736 | } | 736 | } |
| 737 | 737 | ||
| 738 | static struct mem_cgroup *try_get_mem_cgroup_from_mm(struct mm_struct *mm) | 738 | struct mem_cgroup *try_get_mem_cgroup_from_mm(struct mm_struct *mm) |
| 739 | { | 739 | { |
| 740 | struct mem_cgroup *mem = NULL; | 740 | struct mem_cgroup *mem = NULL; |
| 741 | 741 | ||
| @@ -5414,18 +5414,16 @@ static void mem_cgroup_move_task(struct cgroup_subsys *ss, | |||
| 5414 | struct cgroup *old_cont, | 5414 | struct cgroup *old_cont, |
| 5415 | struct task_struct *p) | 5415 | struct task_struct *p) |
| 5416 | { | 5416 | { |
| 5417 | struct mm_struct *mm; | 5417 | struct mm_struct *mm = get_task_mm(p); |
| 5418 | 5418 | ||
| 5419 | if (!mc.to) | ||
| 5420 | /* no need to move charge */ | ||
| 5421 | return; | ||
| 5422 | |||
| 5423 | mm = get_task_mm(p); | ||
| 5424 | if (mm) { | 5419 | if (mm) { |
| 5425 | mem_cgroup_move_charge(mm); | 5420 | if (mc.to) |
| 5421 | mem_cgroup_move_charge(mm); | ||
| 5422 | put_swap_token(mm); | ||
| 5426 | mmput(mm); | 5423 | mmput(mm); |
| 5427 | } | 5424 | } |
| 5428 | mem_cgroup_clear_mc(); | 5425 | if (mc.to) |
| 5426 | mem_cgroup_clear_mc(); | ||
| 5429 | } | 5427 | } |
| 5430 | #else /* !CONFIG_MMU */ | 5428 | #else /* !CONFIG_MMU */ |
| 5431 | static int mem_cgroup_can_attach(struct cgroup_subsys *ss, | 5429 | static int mem_cgroup_can_attach(struct cgroup_subsys *ss, |
diff --git a/mm/thrash.c b/mm/thrash.c index 2372d4ed5dd..6cdf8651138 100644 --- a/mm/thrash.c +++ b/mm/thrash.c | |||
| @@ -21,11 +21,31 @@ | |||
| 21 | #include <linux/mm.h> | 21 | #include <linux/mm.h> |
| 22 | #include <linux/sched.h> | 22 | #include <linux/sched.h> |
| 23 | #include <linux/swap.h> | 23 | #include <linux/swap.h> |
| 24 | #include <linux/memcontrol.h> | ||
| 24 | 25 | ||
| 25 | static DEFINE_SPINLOCK(swap_token_lock); | 26 | static DEFINE_SPINLOCK(swap_token_lock); |
| 26 | struct mm_struct *swap_token_mm; | 27 | struct mm_struct *swap_token_mm; |
| 28 | struct mem_cgroup *swap_token_memcg; | ||
| 27 | static unsigned int global_faults; | 29 | static unsigned int global_faults; |
| 28 | 30 | ||
| 31 | #ifdef CONFIG_CGROUP_MEM_RES_CTLR | ||
| 32 | static struct mem_cgroup *swap_token_memcg_from_mm(struct mm_struct *mm) | ||
| 33 | { | ||
| 34 | struct mem_cgroup *memcg; | ||
| 35 | |||
| 36 | memcg = try_get_mem_cgroup_from_mm(mm); | ||
| 37 | if (memcg) | ||
| 38 | css_put(mem_cgroup_css(memcg)); | ||
| 39 | |||
| 40 | return memcg; | ||
| 41 | } | ||
| 42 | #else | ||
| 43 | static struct mem_cgroup *swap_token_memcg_from_mm(struct mm_struct *mm) | ||
| 44 | { | ||
| 45 | return NULL; | ||
| 46 | } | ||
| 47 | #endif | ||
| 48 | |||
| 29 | void grab_swap_token(struct mm_struct *mm) | 49 | void grab_swap_token(struct mm_struct *mm) |
| 30 | { | 50 | { |
| 31 | int current_interval; | 51 | int current_interval; |
| @@ -38,40 +58,69 @@ void grab_swap_token(struct mm_struct *mm) | |||
| 38 | return; | 58 | return; |
| 39 | 59 | ||
| 40 | /* First come first served */ | 60 | /* First come first served */ |
| 41 | if (swap_token_mm == NULL) { | 61 | if (!swap_token_mm) |
| 42 | mm->token_priority = mm->token_priority + 2; | 62 | goto replace_token; |
| 43 | swap_token_mm = mm; | 63 | |
| 64 | if (mm == swap_token_mm) { | ||
| 65 | mm->token_priority += 2; | ||
| 44 | goto out; | 66 | goto out; |
| 45 | } | 67 | } |
| 46 | 68 | ||
| 47 | if (mm != swap_token_mm) { | 69 | if (current_interval < mm->last_interval) |
| 48 | if (current_interval < mm->last_interval) | 70 | mm->token_priority++; |
| 49 | mm->token_priority++; | 71 | else { |
| 50 | else { | 72 | if (likely(mm->token_priority > 0)) |
| 51 | if (likely(mm->token_priority > 0)) | 73 | mm->token_priority--; |
| 52 | mm->token_priority--; | ||
| 53 | } | ||
| 54 | /* Check if we deserve the token */ | ||
| 55 | if (mm->token_priority > swap_token_mm->token_priority) { | ||
| 56 | mm->token_priority += 2; | ||
| 57 | swap_token_mm = mm; | ||
| 58 | } | ||
| 59 | } else { | ||
| 60 | /* Token holder came in again! */ | ||
| 61 | mm->token_priority += 2; | ||
| 62 | } | 74 | } |
| 63 | 75 | ||
| 76 | /* Check if we deserve the token */ | ||
| 77 | if (mm->token_priority > swap_token_mm->token_priority) | ||
| 78 | goto replace_token; | ||
| 79 | |||
| 64 | out: | 80 | out: |
| 65 | mm->faultstamp = global_faults; | 81 | mm->faultstamp = global_faults; |
| 66 | mm->last_interval = current_interval; | 82 | mm->last_interval = current_interval; |
| 67 | spin_unlock(&swap_token_lock); | 83 | spin_unlock(&swap_token_lock); |
| 84 | return; | ||
| 85 | |||
| 86 | replace_token: | ||
| 87 | mm->token_priority += 2; | ||
| 88 | swap_token_mm = mm; | ||
| 89 | swap_token_memcg = swap_token_memcg_from_mm(mm); | ||
| 90 | goto out; | ||
| 68 | } | 91 | } |
| 69 | 92 | ||
| 70 | /* Called on process exit. */ | 93 | /* Called on process exit. */ |
| 71 | void __put_swap_token(struct mm_struct *mm) | 94 | void __put_swap_token(struct mm_struct *mm) |
| 72 | { | 95 | { |
| 73 | spin_lock(&swap_token_lock); | 96 | spin_lock(&swap_token_lock); |
| 74 | if (likely(mm == swap_token_mm)) | 97 | if (likely(mm == swap_token_mm)) { |
| 75 | swap_token_mm = NULL; | 98 | swap_token_mm = NULL; |
| 99 | swap_token_memcg = NULL; | ||
| 100 | } | ||
| 76 | spin_unlock(&swap_token_lock); | 101 | spin_unlock(&swap_token_lock); |
| 77 | } | 102 | } |
| 103 | |||
| 104 | static bool match_memcg(struct mem_cgroup *a, struct mem_cgroup *b) | ||
| 105 | { | ||
| 106 | if (!a) | ||
| 107 | return true; | ||
| 108 | if (!b) | ||
| 109 | return true; | ||
| 110 | if (a == b) | ||
| 111 | return true; | ||
| 112 | return false; | ||
| 113 | } | ||
| 114 | |||
| 115 | void disable_swap_token(struct mem_cgroup *memcg) | ||
| 116 | { | ||
| 117 | /* memcg reclaim don't disable unrelated mm token. */ | ||
| 118 | if (match_memcg(memcg, swap_token_memcg)) { | ||
| 119 | spin_lock(&swap_token_lock); | ||
| 120 | if (match_memcg(memcg, swap_token_memcg)) { | ||
| 121 | swap_token_mm = NULL; | ||
| 122 | swap_token_memcg = NULL; | ||
| 123 | } | ||
| 124 | spin_unlock(&swap_token_lock); | ||
| 125 | } | ||
| 126 | } | ||
diff --git a/mm/vmscan.c b/mm/vmscan.c index faa0a088f9c..dbe6ea321df 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c | |||
| @@ -2081,7 +2081,7 @@ static unsigned long do_try_to_free_pages(struct zonelist *zonelist, | |||
| 2081 | for (priority = DEF_PRIORITY; priority >= 0; priority--) { | 2081 | for (priority = DEF_PRIORITY; priority >= 0; priority--) { |
| 2082 | sc->nr_scanned = 0; | 2082 | sc->nr_scanned = 0; |
| 2083 | if (!priority) | 2083 | if (!priority) |
| 2084 | disable_swap_token(); | 2084 | disable_swap_token(sc->mem_cgroup); |
| 2085 | total_scanned += shrink_zones(priority, zonelist, sc); | 2085 | total_scanned += shrink_zones(priority, zonelist, sc); |
| 2086 | /* | 2086 | /* |
| 2087 | * Don't shrink slabs when reclaiming memory from | 2087 | * Don't shrink slabs when reclaiming memory from |
| @@ -2407,7 +2407,7 @@ loop_again: | |||
| 2407 | 2407 | ||
| 2408 | /* The swap token gets in the way of swapout... */ | 2408 | /* The swap token gets in the way of swapout... */ |
| 2409 | if (!priority) | 2409 | if (!priority) |
| 2410 | disable_swap_token(); | 2410 | disable_swap_token(NULL); |
| 2411 | 2411 | ||
| 2412 | all_zones_ok = 1; | 2412 | all_zones_ok = 1; |
| 2413 | balanced = 0; | 2413 | balanced = 0; |
