diff options
Diffstat (limited to 'mm/oom_kill.c')
-rw-r--r-- | mm/oom_kill.c | 40 |
1 files changed, 29 insertions, 11 deletions
diff --git a/mm/oom_kill.c b/mm/oom_kill.c index 6f6e04c40c9..7c8488f6a3f 100644 --- a/mm/oom_kill.c +++ b/mm/oom_kill.c | |||
@@ -362,10 +362,10 @@ static void dump_tasks(const struct mem_cgroup *mem) | |||
362 | static void dump_header(struct task_struct *p, gfp_t gfp_mask, int order, | 362 | static void dump_header(struct task_struct *p, gfp_t gfp_mask, int order, |
363 | struct mem_cgroup *mem) | 363 | struct mem_cgroup *mem) |
364 | { | 364 | { |
365 | task_lock(current); | ||
365 | pr_warning("%s invoked oom-killer: gfp_mask=0x%x, order=%d, " | 366 | pr_warning("%s invoked oom-killer: gfp_mask=0x%x, order=%d, " |
366 | "oom_adj=%d\n", | 367 | "oom_adj=%d\n", |
367 | current->comm, gfp_mask, order, current->signal->oom_adj); | 368 | current->comm, gfp_mask, order, current->signal->oom_adj); |
368 | task_lock(current); | ||
369 | cpuset_print_task_mems_allowed(current); | 369 | cpuset_print_task_mems_allowed(current); |
370 | task_unlock(current); | 370 | task_unlock(current); |
371 | dump_stack(); | 371 | dump_stack(); |
@@ -436,8 +436,11 @@ static int oom_kill_process(struct task_struct *p, gfp_t gfp_mask, int order, | |||
436 | unsigned long points, struct mem_cgroup *mem, | 436 | unsigned long points, struct mem_cgroup *mem, |
437 | const char *message) | 437 | const char *message) |
438 | { | 438 | { |
439 | struct task_struct *c; | 439 | struct task_struct *victim = p; |
440 | struct task_struct *child; | ||
440 | struct task_struct *t = p; | 441 | struct task_struct *t = p; |
442 | unsigned long victim_points = 0; | ||
443 | struct timespec uptime; | ||
441 | 444 | ||
442 | if (printk_ratelimit()) | 445 | if (printk_ratelimit()) |
443 | dump_header(p, gfp_mask, order, mem); | 446 | dump_header(p, gfp_mask, order, mem); |
@@ -451,22 +454,37 @@ static int oom_kill_process(struct task_struct *p, gfp_t gfp_mask, int order, | |||
451 | return 0; | 454 | return 0; |
452 | } | 455 | } |
453 | 456 | ||
454 | printk(KERN_ERR "%s: kill process %d (%s) score %li or a child\n", | 457 | task_lock(p); |
455 | message, task_pid_nr(p), p->comm, points); | 458 | pr_err("%s: Kill process %d (%s) score %lu or sacrifice child\n", |
459 | message, task_pid_nr(p), p->comm, points); | ||
460 | task_unlock(p); | ||
456 | 461 | ||
457 | /* Try to kill a child first */ | 462 | /* |
463 | * If any of p's children has a different mm and is eligible for kill, | ||
464 | * the one with the highest badness() score is sacrificed for its | ||
465 | * parent. This attempts to lose the minimal amount of work done while | ||
466 | * still freeing memory. | ||
467 | */ | ||
468 | do_posix_clock_monotonic_gettime(&uptime); | ||
458 | do { | 469 | do { |
459 | list_for_each_entry(c, &t->children, sibling) { | 470 | list_for_each_entry(child, &t->children, sibling) { |
460 | if (c->mm == p->mm) | 471 | unsigned long child_points; |
472 | |||
473 | if (child->mm == p->mm) | ||
461 | continue; | 474 | continue; |
462 | if (mem && !task_in_mem_cgroup(c, mem)) | 475 | if (mem && !task_in_mem_cgroup(child, mem)) |
463 | continue; | 476 | continue; |
464 | if (!oom_kill_task(c)) | 477 | |
465 | return 0; | 478 | /* badness() returns 0 if the thread is unkillable */ |
479 | child_points = badness(child, uptime.tv_sec); | ||
480 | if (child_points > victim_points) { | ||
481 | victim = child; | ||
482 | victim_points = child_points; | ||
483 | } | ||
466 | } | 484 | } |
467 | } while_each_thread(p, t); | 485 | } while_each_thread(p, t); |
468 | 486 | ||
469 | return oom_kill_task(p); | 487 | return oom_kill_task(victim); |
470 | } | 488 | } |
471 | 489 | ||
472 | #ifdef CONFIG_CGROUP_MEM_RES_CTLR | 490 | #ifdef CONFIG_CGROUP_MEM_RES_CTLR |