diff options
Diffstat (limited to 'mm/oom_kill.c')
-rw-r--r-- | mm/oom_kill.c | 52 |
1 files changed, 32 insertions, 20 deletions
diff --git a/mm/oom_kill.c b/mm/oom_kill.c index 7dcca55ede7c..3100bc57036b 100644 --- a/mm/oom_kill.c +++ b/mm/oom_kill.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <linux/memcontrol.h> | 31 | #include <linux/memcontrol.h> |
32 | #include <linux/mempolicy.h> | 32 | #include <linux/mempolicy.h> |
33 | #include <linux/security.h> | 33 | #include <linux/security.h> |
34 | #include <linux/ptrace.h> | ||
34 | 35 | ||
35 | int sysctl_panic_on_oom; | 36 | int sysctl_panic_on_oom; |
36 | int sysctl_oom_kill_allocating_task; | 37 | int sysctl_oom_kill_allocating_task; |
@@ -292,13 +293,15 @@ static struct task_struct *select_bad_process(unsigned int *ppoints, | |||
292 | unsigned long totalpages, struct mem_cgroup *mem, | 293 | unsigned long totalpages, struct mem_cgroup *mem, |
293 | const nodemask_t *nodemask) | 294 | const nodemask_t *nodemask) |
294 | { | 295 | { |
295 | struct task_struct *p; | 296 | struct task_struct *g, *p; |
296 | struct task_struct *chosen = NULL; | 297 | struct task_struct *chosen = NULL; |
297 | *ppoints = 0; | 298 | *ppoints = 0; |
298 | 299 | ||
299 | for_each_process(p) { | 300 | do_each_thread(g, p) { |
300 | unsigned int points; | 301 | unsigned int points; |
301 | 302 | ||
303 | if (!p->mm) | ||
304 | continue; | ||
302 | if (oom_unkillable_task(p, mem, nodemask)) | 305 | if (oom_unkillable_task(p, mem, nodemask)) |
303 | continue; | 306 | continue; |
304 | 307 | ||
@@ -314,22 +317,29 @@ static struct task_struct *select_bad_process(unsigned int *ppoints, | |||
314 | if (test_tsk_thread_flag(p, TIF_MEMDIE)) | 317 | if (test_tsk_thread_flag(p, TIF_MEMDIE)) |
315 | return ERR_PTR(-1UL); | 318 | return ERR_PTR(-1UL); |
316 | 319 | ||
317 | /* | 320 | if (p->flags & PF_EXITING) { |
318 | * This is in the process of releasing memory so wait for it | 321 | /* |
319 | * to finish before killing some other task by mistake. | 322 | * If p is the current task and is in the process of |
320 | * | 323 | * releasing memory, we allow the "kill" to set |
321 | * However, if p is the current task, we allow the 'kill' to | 324 | * TIF_MEMDIE, which will allow it to gain access to |
322 | * go ahead if it is exiting: this will simply set TIF_MEMDIE, | 325 | * memory reserves. Otherwise, it may stall forever. |
323 | * which will allow it to gain access to memory reserves in | 326 | * |
324 | * the process of exiting and releasing its resources. | 327 | * The loop isn't broken here, however, in case other |
325 | * Otherwise we could get an easy OOM deadlock. | 328 | * threads are found to have already been oom killed. |
326 | */ | 329 | */ |
327 | if (thread_group_empty(p) && (p->flags & PF_EXITING) && p->mm) { | 330 | if (p == current) { |
328 | if (p != current) | 331 | chosen = p; |
329 | return ERR_PTR(-1UL); | 332 | *ppoints = 1000; |
330 | 333 | } else { | |
331 | chosen = p; | 334 | /* |
332 | *ppoints = 1000; | 335 | * If this task is not being ptraced on exit, |
336 | * then wait for it to finish before killing | ||
337 | * some other task unnecessarily. | ||
338 | */ | ||
339 | if (!(task_ptrace(p->group_leader) & | ||
340 | PT_TRACE_EXIT)) | ||
341 | return ERR_PTR(-1UL); | ||
342 | } | ||
333 | } | 343 | } |
334 | 344 | ||
335 | points = oom_badness(p, mem, nodemask, totalpages); | 345 | points = oom_badness(p, mem, nodemask, totalpages); |
@@ -337,7 +347,7 @@ static struct task_struct *select_bad_process(unsigned int *ppoints, | |||
337 | chosen = p; | 347 | chosen = p; |
338 | *ppoints = points; | 348 | *ppoints = points; |
339 | } | 349 | } |
340 | } | 350 | } while_each_thread(g, p); |
341 | 351 | ||
342 | return chosen; | 352 | return chosen; |
343 | } | 353 | } |
@@ -396,7 +406,7 @@ static void dump_header(struct task_struct *p, gfp_t gfp_mask, int order, | |||
396 | task_unlock(current); | 406 | task_unlock(current); |
397 | dump_stack(); | 407 | dump_stack(); |
398 | mem_cgroup_print_oom_info(mem, p); | 408 | mem_cgroup_print_oom_info(mem, p); |
399 | show_mem(); | 409 | __show_mem(SHOW_MEM_FILTER_NODES); |
400 | if (sysctl_oom_dump_tasks) | 410 | if (sysctl_oom_dump_tasks) |
401 | dump_tasks(mem, nodemask); | 411 | dump_tasks(mem, nodemask); |
402 | } | 412 | } |
@@ -491,6 +501,8 @@ static int oom_kill_process(struct task_struct *p, gfp_t gfp_mask, int order, | |||
491 | list_for_each_entry(child, &t->children, sibling) { | 501 | list_for_each_entry(child, &t->children, sibling) { |
492 | unsigned int child_points; | 502 | unsigned int child_points; |
493 | 503 | ||
504 | if (child->mm == p->mm) | ||
505 | continue; | ||
494 | /* | 506 | /* |
495 | * oom_badness() returns 0 if the thread is unkillable | 507 | * oom_badness() returns 0 if the thread is unkillable |
496 | */ | 508 | */ |