diff options
Diffstat (limited to 'mm/oom_kill.c')
-rw-r--r-- | mm/oom_kill.c | 53 |
1 files changed, 30 insertions, 23 deletions
diff --git a/mm/oom_kill.c b/mm/oom_kill.c index bada3d03119f..20f41b082e16 100644 --- a/mm/oom_kill.c +++ b/mm/oom_kill.c | |||
@@ -204,16 +204,30 @@ static struct task_struct *select_bad_process(unsigned long *ppoints) | |||
204 | do_posix_clock_monotonic_gettime(&uptime); | 204 | do_posix_clock_monotonic_gettime(&uptime); |
205 | do_each_thread(g, p) { | 205 | do_each_thread(g, p) { |
206 | unsigned long points; | 206 | unsigned long points; |
207 | int releasing; | ||
208 | 207 | ||
209 | /* skip kernel threads */ | 208 | /* |
209 | * skip kernel threads and tasks which have already released | ||
210 | * their mm. | ||
211 | */ | ||
210 | if (!p->mm) | 212 | if (!p->mm) |
211 | continue; | 213 | continue; |
212 | /* skip the init task with pid == 1 */ | 214 | /* skip the init task */ |
213 | if (p->pid == 1) | 215 | if (is_init(p)) |
214 | continue; | 216 | continue; |
215 | 217 | ||
216 | /* | 218 | /* |
219 | * This task already has access to memory reserves and is | ||
220 | * being killed. Don't allow any other task access to the | ||
221 | * memory reserve. | ||
222 | * | ||
223 | * Note: this may have a chance of deadlock if it gets | ||
224 | * blocked waiting for another task which itself is waiting | ||
225 | * for memory. Is there a better alternative? | ||
226 | */ | ||
227 | if (test_tsk_thread_flag(p, TIF_MEMDIE)) | ||
228 | return ERR_PTR(-1UL); | ||
229 | |||
230 | /* | ||
217 | * This is in the process of releasing memory so wait for it | 231 | * This is in the process of releasing memory so wait for it |
218 | * to finish before killing some other task by mistake. | 232 | * to finish before killing some other task by mistake. |
219 | * | 233 | * |
@@ -221,21 +235,16 @@ static struct task_struct *select_bad_process(unsigned long *ppoints) | |||
221 | * go ahead if it is exiting: this will simply set TIF_MEMDIE, | 235 | * go ahead if it is exiting: this will simply set TIF_MEMDIE, |
222 | * which will allow it to gain access to memory reserves in | 236 | * which will allow it to gain access to memory reserves in |
223 | * the process of exiting and releasing its resources. | 237 | * the process of exiting and releasing its resources. |
224 | * Otherwise we could get an OOM deadlock. | 238 | * Otherwise we could get an easy OOM deadlock. |
225 | */ | 239 | */ |
226 | releasing = test_tsk_thread_flag(p, TIF_MEMDIE) || | 240 | if (p->flags & PF_EXITING) { |
227 | p->flags & PF_EXITING; | 241 | if (p != current) |
228 | if (releasing) { | 242 | return ERR_PTR(-1UL); |
229 | /* PF_DEAD tasks have already released their mm */ | 243 | |
230 | if (p->flags & PF_DEAD) | 244 | chosen = p; |
231 | continue; | 245 | *ppoints = ULONG_MAX; |
232 | if (p->flags & PF_EXITING && p == current) { | ||
233 | chosen = p; | ||
234 | *ppoints = ULONG_MAX; | ||
235 | break; | ||
236 | } | ||
237 | return ERR_PTR(-1UL); | ||
238 | } | 246 | } |
247 | |||
239 | if (p->oomkilladj == OOM_DISABLE) | 248 | if (p->oomkilladj == OOM_DISABLE) |
240 | continue; | 249 | continue; |
241 | 250 | ||
@@ -245,6 +254,7 @@ static struct task_struct *select_bad_process(unsigned long *ppoints) | |||
245 | *ppoints = points; | 254 | *ppoints = points; |
246 | } | 255 | } |
247 | } while_each_thread(g, p); | 256 | } while_each_thread(g, p); |
257 | |||
248 | return chosen; | 258 | return chosen; |
249 | } | 259 | } |
250 | 260 | ||
@@ -255,20 +265,17 @@ static struct task_struct *select_bad_process(unsigned long *ppoints) | |||
255 | */ | 265 | */ |
256 | static void __oom_kill_task(struct task_struct *p, const char *message) | 266 | static void __oom_kill_task(struct task_struct *p, const char *message) |
257 | { | 267 | { |
258 | if (p->pid == 1) { | 268 | if (is_init(p)) { |
259 | WARN_ON(1); | 269 | WARN_ON(1); |
260 | printk(KERN_WARNING "tried to kill init!\n"); | 270 | printk(KERN_WARNING "tried to kill init!\n"); |
261 | return; | 271 | return; |
262 | } | 272 | } |
263 | 273 | ||
264 | task_lock(p); | 274 | if (!p->mm) { |
265 | if (!p->mm || p->mm == &init_mm) { | ||
266 | WARN_ON(1); | 275 | WARN_ON(1); |
267 | printk(KERN_WARNING "tried to kill an mm-less task!\n"); | 276 | printk(KERN_WARNING "tried to kill an mm-less task!\n"); |
268 | task_unlock(p); | ||
269 | return; | 277 | return; |
270 | } | 278 | } |
271 | task_unlock(p); | ||
272 | 279 | ||
273 | if (message) { | 280 | if (message) { |
274 | printk(KERN_ERR "%s: Killed process %d (%s).\n", | 281 | printk(KERN_ERR "%s: Killed process %d (%s).\n", |
@@ -302,7 +309,7 @@ static int oom_kill_task(struct task_struct *p, const char *message) | |||
302 | * However, this is of no concern to us. | 309 | * However, this is of no concern to us. |
303 | */ | 310 | */ |
304 | 311 | ||
305 | if (mm == NULL || mm == &init_mm) | 312 | if (mm == NULL) |
306 | return 1; | 313 | return 1; |
307 | 314 | ||
308 | __oom_kill_task(p, message); | 315 | __oom_kill_task(p, message); |