Commit | Line | Data |
---|---|---|
355b0502 GKH |
1 | /* drivers/misc/lowmemorykiller.c |
2 | * | |
3 | * The lowmemorykiller driver lets user-space specify a set of memory thresholds | |
940f77b0 DR |
4 | * where processes with a range of oom_score_adj values will get killed. Specify |
5 | * the minimum oom_score_adj values in | |
6 | * /sys/module/lowmemorykiller/parameters/adj and the number of free pages in | |
7 | * /sys/module/lowmemorykiller/parameters/minfree. Both files take a comma | |
8 | * separated list of numbers in ascending order. | |
355b0502 GKH |
9 | * |
10 | * For example, write "0,8" to /sys/module/lowmemorykiller/parameters/adj and | |
3bf5d65f | 11 | * "1024,4096" to /sys/module/lowmemorykiller/parameters/minfree to kill |
940f77b0 DR |
12 | * processes with a oom_score_adj value of 8 or higher when the free memory |
13 | * drops below 4096 pages and kill processes with a oom_score_adj value of 0 or | |
14 | * higher when the free memory drops below 1024 pages. | |
355b0502 GKH |
15 | * |
16 | * The driver considers memory used for caches to be free, but if a large | |
17 | * percentage of the cached memory is locked this can be very inaccurate | |
18 | * and processes may not get killed until the normal oom killer is triggered. | |
19 | * | |
20 | * Copyright (C) 2007-2008 Google, Inc. | |
21 | * | |
22 | * This software is licensed under the terms of the GNU General Public | |
23 | * License version 2, as published by the Free Software Foundation, and | |
24 | * may be copied, distributed, and modified under those terms. | |
25 | * | |
26 | * This program is distributed in the hope that it will be useful, | |
27 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
28 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
29 | * GNU General Public License for more details. | |
30 | * | |
31 | */ | |
32 | ||
6b83f915 DV |
33 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
34 | ||
380b6549 PG |
35 | #include <linux/init.h> |
36 | #include <linux/moduleparam.h> | |
355b0502 GKH |
37 | #include <linux/kernel.h> |
38 | #include <linux/mm.h> | |
39 | #include <linux/oom.h> | |
40 | #include <linux/sched.h> | |
eeb0f4f3 | 41 | #include <linux/swap.h> |
294b2711 | 42 | #include <linux/rcupdate.h> |
4755b72e SM |
43 | #include <linux/profile.h> |
44 | #include <linux/notifier.h> | |
355b0502 | 45 | |
36f16ff2 | 46 | static u32 lowmem_debug_level = 1; |
a9c58b90 | 47 | static short lowmem_adj[6] = { |
355b0502 GKH |
48 | 0, |
49 | 1, | |
50 | 6, | |
51 | 12, | |
52 | }; | |
b33061fb | 53 | |
355b0502 | 54 | static int lowmem_adj_size = 4; |
624b2250 | 55 | static int lowmem_minfree[6] = { |
355b0502 GKH |
56 | 3 * 512, /* 6MB */ |
57 | 2 * 1024, /* 8MB */ | |
58 | 4 * 1024, /* 16MB */ | |
59 | 16 * 1024, /* 64MB */ | |
60 | }; | |
b33061fb | 61 | |
355b0502 GKH |
62 | static int lowmem_minfree_size = 4; |
63 | ||
e5d7965f | 64 | static unsigned long lowmem_deathpending_timeout; |
4755b72e | 65 | |
355b0502 GKH |
66 | #define lowmem_print(level, x...) \ |
67 | do { \ | |
68 | if (lowmem_debug_level >= (level)) \ | |
6b83f915 | 69 | pr_info(x); \ |
355b0502 GKH |
70 | } while (0) |
71 | ||
7dc19d5a DC |
72 | static unsigned long lowmem_count(struct shrinker *s, |
73 | struct shrink_control *sc) | |
74 | { | |
75 | return global_page_state(NR_ACTIVE_ANON) + | |
76 | global_page_state(NR_ACTIVE_FILE) + | |
77 | global_page_state(NR_INACTIVE_ANON) + | |
78 | global_page_state(NR_INACTIVE_FILE); | |
79 | } | |
80 | ||
81 | static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc) | |
355b0502 | 82 | { |
95670001 | 83 | struct task_struct *tsk; |
355b0502 | 84 | struct task_struct *selected = NULL; |
7dc19d5a | 85 | unsigned long rem = 0; |
355b0502 GKH |
86 | int tasksize; |
87 | int i; | |
a9c58b90 | 88 | short min_score_adj = OOM_SCORE_ADJ_MAX + 1; |
cc635da2 | 89 | int minfree = 0; |
355b0502 | 90 | int selected_tasksize = 0; |
a9c58b90 | 91 | short selected_oom_score_adj; |
355b0502 | 92 | int array_size = ARRAY_SIZE(lowmem_adj); |
eeb0f4f3 | 93 | int other_free = global_page_state(NR_FREE_PAGES) - totalreserve_pages; |
71b2c82b | 94 | int other_file = global_page_state(NR_FILE_PAGES) - |
058dbde9 VM |
95 | global_page_state(NR_SHMEM) - |
96 | total_swapcache_pages(); | |
355b0502 GKH |
97 | |
98 | if (lowmem_adj_size < array_size) | |
99 | array_size = lowmem_adj_size; | |
100 | if (lowmem_minfree_size < array_size) | |
101 | array_size = lowmem_minfree_size; | |
102 | for (i = 0; i < array_size; i++) { | |
cc635da2 CC |
103 | minfree = lowmem_minfree[i]; |
104 | if (other_free < minfree && other_file < minfree) { | |
940f77b0 | 105 | min_score_adj = lowmem_adj[i]; |
355b0502 GKH |
106 | break; |
107 | } | |
108 | } | |
7dc19d5a DC |
109 | |
110 | lowmem_print(3, "lowmem_scan %lu, %x, ofree %d %d, ma %hd\n", | |
f8b053e3 IC |
111 | sc->nr_to_scan, sc->gfp_mask, other_free, |
112 | other_file, min_score_adj); | |
7dc19d5a DC |
113 | |
114 | if (min_score_adj == OOM_SCORE_ADJ_MAX + 1) { | |
115 | lowmem_print(5, "lowmem_scan %lu, %x, return 0\n", | |
116 | sc->nr_to_scan, sc->gfp_mask); | |
117 | return 0; | |
355b0502 | 118 | } |
7dc19d5a | 119 | |
940f77b0 | 120 | selected_oom_score_adj = min_score_adj; |
355b0502 | 121 | |
294b2711 | 122 | rcu_read_lock(); |
95670001 AV |
123 | for_each_process(tsk) { |
124 | struct task_struct *p; | |
a9c58b90 | 125 | short oom_score_adj; |
355b0502 | 126 | |
9823ec9d | 127 | if (tsk->flags & PF_KTHREAD) |
355b0502 | 128 | continue; |
9823ec9d | 129 | |
95670001 AV |
130 | p = find_lock_task_mm(tsk); |
131 | if (!p) | |
132 | continue; | |
133 | ||
ae25d43c | 134 | if (task_lmk_waiting(p) && |
83dbbdbb DR |
135 | time_before_eq(jiffies, lowmem_deathpending_timeout)) { |
136 | task_unlock(p); | |
137 | rcu_read_unlock(); | |
138 | return 0; | |
139 | } | |
940f77b0 DR |
140 | oom_score_adj = p->signal->oom_score_adj; |
141 | if (oom_score_adj < min_score_adj) { | |
355b0502 GKH |
142 | task_unlock(p); |
143 | continue; | |
144 | } | |
95670001 | 145 | tasksize = get_mm_rss(p->mm); |
355b0502 GKH |
146 | task_unlock(p); |
147 | if (tasksize <= 0) | |
148 | continue; | |
149 | if (selected) { | |
940f77b0 | 150 | if (oom_score_adj < selected_oom_score_adj) |
355b0502 | 151 | continue; |
940f77b0 | 152 | if (oom_score_adj == selected_oom_score_adj && |
355b0502 GKH |
153 | tasksize <= selected_tasksize) |
154 | continue; | |
155 | } | |
156 | selected = p; | |
157 | selected_tasksize = tasksize; | |
940f77b0 | 158 | selected_oom_score_adj = oom_score_adj; |
cc635da2 CC |
159 | lowmem_print(2, "select '%s' (%d), adj %hd, size %d, to kill\n", |
160 | p->comm, p->pid, oom_score_adj, tasksize); | |
355b0502 GKH |
161 | } |
162 | if (selected) { | |
e1099a69 | 163 | task_lock(selected); |
3a81fc20 | 164 | send_sig(SIGKILL, selected, 0); |
3a81fc20 | 165 | if (selected->mm) |
77ed2c57 | 166 | task_set_lmk_waiting(selected); |
e1099a69 | 167 | task_unlock(selected); |
cc635da2 CC |
168 | lowmem_print(1, "Killing '%s' (%d), adj %hd,\n" |
169 | " to free %ldkB on behalf of '%s' (%d) because\n" | |
170 | " cache %ldkB is below limit %ldkB for oom_score_adj %hd\n" | |
171 | " Free memory is %ldkB above reserved\n", | |
172 | selected->comm, selected->pid, | |
173 | selected_oom_score_adj, | |
174 | selected_tasksize * (long)(PAGE_SIZE / 1024), | |
175 | current->comm, current->pid, | |
176 | other_file * (long)(PAGE_SIZE / 1024), | |
177 | minfree * (long)(PAGE_SIZE / 1024), | |
178 | min_score_adj, | |
179 | other_free * (long)(PAGE_SIZE / 1024)); | |
e1099a69 | 180 | lowmem_deathpending_timeout = jiffies + HZ; |
7dc19d5a | 181 | rem += selected_tasksize; |
355b0502 | 182 | } |
3a81fc20 | 183 | |
7dc19d5a | 184 | lowmem_print(4, "lowmem_scan %lu, %x, return %lu\n", |
cae9bf11 | 185 | sc->nr_to_scan, sc->gfp_mask, rem); |
294b2711 | 186 | rcu_read_unlock(); |
355b0502 GKH |
187 | return rem; |
188 | } | |
189 | ||
190 | static struct shrinker lowmem_shrinker = { | |
7dc19d5a DC |
191 | .scan_objects = lowmem_scan, |
192 | .count_objects = lowmem_count, | |
355b0502 GKH |
193 | .seeks = DEFAULT_SEEKS * 16 |
194 | }; | |
195 | ||
196 | static int __init lowmem_init(void) | |
197 | { | |
198 | register_shrinker(&lowmem_shrinker); | |
199 | return 0; | |
200 | } | |
380b6549 | 201 | device_initcall(lowmem_init); |
355b0502 | 202 | |
380b6549 PG |
203 | /* |
204 | * not really modular, but the easiest way to keep compat with existing | |
205 | * bootargs behaviour is to continue using module_param here. | |
206 | */ | |
355b0502 | 207 | module_param_named(cost, lowmem_shrinker.seeks, int, S_IRUGO | S_IWUSR); |
a9c58b90 | 208 | module_param_array_named(adj, lowmem_adj, short, &lowmem_adj_size, |
355b0502 GKH |
209 | S_IRUGO | S_IWUSR); |
210 | module_param_array_named(minfree, lowmem_minfree, uint, &lowmem_minfree_size, | |
211 | S_IRUGO | S_IWUSR); | |
212 | module_param_named(debug_level, lowmem_debug_level, uint, S_IRUGO | S_IWUSR); | |
213 |