aboutsummaryrefslogtreecommitdiffstats
path: root/mm
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 /mm
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>
Diffstat (limited to 'mm')
-rw-r--r--mm/memcontrol.c16
-rw-r--r--mm/thrash.c87
-rw-r--r--mm/vmscan.c4
3 files changed, 77 insertions, 30 deletions
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;