aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>2011-06-15 18:08:13 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2011-06-15 23:03:59 -0400
commita433658c30974fc87ba3ff52d7e4e6299762aa3d (patch)
tree8df65e22af520ca5c020281763e6874d0bb51bc5
parente1bbd19bc4afef7adb80cca163800391c4f5773d (diff)
vmscan,memcg: memcg aware swap token
Currently, memcg reclaim can disable swap token even if the swap token mm doesn't belong in its memory cgroup. It's slightly risky. If an admin creates very small mem-cgroup and silly guy runs contentious heavy memory pressure workload, every tasks are going to lose swap token and then system may become unresponsive. That's bad. This patch adds 'memcg' parameter into disable_swap_token(). and if the parameter doesn't match swap token, VM doesn't disable it. [akpm@linux-foundation.org: coding-style fixes] Signed-off-by: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com> Reviewed-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> Reviewed-by: Rik van Riel<riel@redhat.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--include/linux/memcontrol.h6
-rw-r--r--include/linux/swap.h8
-rw-r--r--mm/memcontrol.c16
-rw-r--r--mm/thrash.c87
-rw-r--r--mm/vmscan.c4
5 files changed, 85 insertions, 36 deletions
diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h
index 9724a38ee69d..50940da6adf3 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
85extern struct mem_cgroup *try_get_mem_cgroup_from_page(struct page *page); 85extern struct mem_cgroup *try_get_mem_cgroup_from_page(struct page *page);
86extern struct mem_cgroup *mem_cgroup_from_task(struct task_struct *p); 86extern struct mem_cgroup *mem_cgroup_from_task(struct task_struct *p);
87extern struct mem_cgroup *try_get_mem_cgroup_from_mm(struct mm_struct *mm);
87 88
88static inline 89static inline
89int mm_match_cgroup(const struct mm_struct *mm, const struct mem_cgroup *cgroup) 90int 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
250static inline struct mem_cgroup *try_get_mem_cgroup_from_mm(struct mm_struct *mm)
251{
252 return NULL;
253}
254
249static inline int mm_match_cgroup(struct mm_struct *mm, struct mem_cgroup *mem) 255static 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 384eb5fe530b..e70564647039 100644
--- a/include/linux/swap.h
+++ b/include/linux/swap.h
@@ -358,6 +358,7 @@ struct backing_dev_info;
358extern struct mm_struct *swap_token_mm; 358extern struct mm_struct *swap_token_mm;
359extern void grab_swap_token(struct mm_struct *); 359extern void grab_swap_token(struct mm_struct *);
360extern void __put_swap_token(struct mm_struct *); 360extern void __put_swap_token(struct mm_struct *);
361extern void disable_swap_token(struct mem_cgroup *memcg);
361 362
362static inline int has_swap_token(struct mm_struct *mm) 363static 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
373static 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
379extern void 375extern void
380mem_cgroup_uncharge_swapcache(struct page *page, swp_entry_t ent, bool swapout); 376mem_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
503static inline void disable_swap_token(void) 499static 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 bd9052a5d3ad..e37c44d88d46 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
738static struct mem_cgroup *try_get_mem_cgroup_from_mm(struct mm_struct *mm) 738struct 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 */
5431static int mem_cgroup_can_attach(struct cgroup_subsys *ss, 5429static int mem_cgroup_can_attach(struct cgroup_subsys *ss,
diff --git a/mm/thrash.c b/mm/thrash.c
index 2372d4ed5dd8..6cdf86511385 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
25static DEFINE_SPINLOCK(swap_token_lock); 26static DEFINE_SPINLOCK(swap_token_lock);
26struct mm_struct *swap_token_mm; 27struct mm_struct *swap_token_mm;
28struct mem_cgroup *swap_token_memcg;
27static unsigned int global_faults; 29static unsigned int global_faults;
28 30
31#ifdef CONFIG_CGROUP_MEM_RES_CTLR
32static 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
43static struct mem_cgroup *swap_token_memcg_from_mm(struct mm_struct *mm)
44{
45 return NULL;
46}
47#endif
48
29void grab_swap_token(struct mm_struct *mm) 49void 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
64out: 80out:
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
86replace_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. */
71void __put_swap_token(struct mm_struct *mm) 94void __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
104static 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
115void 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 faa0a088f9cc..dbe6ea321df4 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;