OSDN Git Service

6cdf86511385b019619d2d12b119161ce5c91752
[android-x86/kernel.git] / mm / thrash.c
1 /*
2  * mm/thrash.c
3  *
4  * Copyright (C) 2004, Red Hat, Inc.
5  * Copyright (C) 2004, Rik van Riel <riel@redhat.com>
6  * Released under the GPL, see the file COPYING for details.
7  *
8  * Simple token based thrashing protection, using the algorithm
9  * described in:  http://www.cs.wm.edu/~sjiang/token.pdf
10  *
11  * Sep 2006, Ashwin Chaugule <ashwin.chaugule@celunite.com>
12  * Improved algorithm to pass token:
13  * Each task has a priority which is incremented if it contended
14  * for the token in an interval less than its previous attempt.
15  * If the token is acquired, that task's priority is boosted to prevent
16  * the token from bouncing around too often and to let the task make
17  * some progress in its execution.
18  */
19
20 #include <linux/jiffies.h>
21 #include <linux/mm.h>
22 #include <linux/sched.h>
23 #include <linux/swap.h>
24 #include <linux/memcontrol.h>
25
26 static DEFINE_SPINLOCK(swap_token_lock);
27 struct mm_struct *swap_token_mm;
28 struct mem_cgroup *swap_token_memcg;
29 static unsigned int global_faults;
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
49 void grab_swap_token(struct mm_struct *mm)
50 {
51         int current_interval;
52
53         global_faults++;
54
55         current_interval = global_faults - mm->faultstamp;
56
57         if (!spin_trylock(&swap_token_lock))
58                 return;
59
60         /* First come first served */
61         if (!swap_token_mm)
62                 goto replace_token;
63
64         if (mm == swap_token_mm) {
65                 mm->token_priority += 2;
66                 goto out;
67         }
68
69         if (current_interval < mm->last_interval)
70                 mm->token_priority++;
71         else {
72                 if (likely(mm->token_priority > 0))
73                         mm->token_priority--;
74         }
75
76         /* Check if we deserve the token */
77         if (mm->token_priority > swap_token_mm->token_priority)
78                 goto replace_token;
79
80 out:
81         mm->faultstamp = global_faults;
82         mm->last_interval = current_interval;
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;
91 }
92
93 /* Called on process exit. */
94 void __put_swap_token(struct mm_struct *mm)
95 {
96         spin_lock(&swap_token_lock);
97         if (likely(mm == swap_token_mm)) {
98                 swap_token_mm = NULL;
99                 swap_token_memcg = NULL;
100         }
101         spin_unlock(&swap_token_lock);
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 }