diff options
Diffstat (limited to 'mm/oom_kill.c')
| -rw-r--r-- | mm/oom_kill.c | 51 |
1 files changed, 29 insertions, 22 deletions
diff --git a/mm/oom_kill.c b/mm/oom_kill.c index 1e4a600a6163..054ff47c4478 100644 --- a/mm/oom_kill.c +++ b/mm/oom_kill.c | |||
| @@ -47,19 +47,21 @@ static DEFINE_SPINLOCK(zone_scan_lock); | |||
| 47 | #ifdef CONFIG_NUMA | 47 | #ifdef CONFIG_NUMA |
| 48 | /** | 48 | /** |
| 49 | * has_intersects_mems_allowed() - check task eligiblity for kill | 49 | * has_intersects_mems_allowed() - check task eligiblity for kill |
| 50 | * @tsk: task struct of which task to consider | 50 | * @start: task struct of which task to consider |
| 51 | * @mask: nodemask passed to page allocator for mempolicy ooms | 51 | * @mask: nodemask passed to page allocator for mempolicy ooms |
| 52 | * | 52 | * |
| 53 | * Task eligibility is determined by whether or not a candidate task, @tsk, | 53 | * Task eligibility is determined by whether or not a candidate task, @tsk, |
| 54 | * shares the same mempolicy nodes as current if it is bound by such a policy | 54 | * shares the same mempolicy nodes as current if it is bound by such a policy |
| 55 | * and whether or not it has the same set of allowed cpuset nodes. | 55 | * and whether or not it has the same set of allowed cpuset nodes. |
| 56 | */ | 56 | */ |
| 57 | static bool has_intersects_mems_allowed(struct task_struct *tsk, | 57 | static bool has_intersects_mems_allowed(struct task_struct *start, |
| 58 | const nodemask_t *mask) | 58 | const nodemask_t *mask) |
| 59 | { | 59 | { |
| 60 | struct task_struct *start = tsk; | 60 | struct task_struct *tsk; |
| 61 | bool ret = false; | ||
| 61 | 62 | ||
| 62 | do { | 63 | rcu_read_lock(); |
| 64 | for_each_thread(start, tsk) { | ||
| 63 | if (mask) { | 65 | if (mask) { |
| 64 | /* | 66 | /* |
| 65 | * If this is a mempolicy constrained oom, tsk's | 67 | * If this is a mempolicy constrained oom, tsk's |
| @@ -67,19 +69,20 @@ static bool has_intersects_mems_allowed(struct task_struct *tsk, | |||
| 67 | * mempolicy intersects current, otherwise it may be | 69 | * mempolicy intersects current, otherwise it may be |
| 68 | * needlessly killed. | 70 | * needlessly killed. |
| 69 | */ | 71 | */ |
| 70 | if (mempolicy_nodemask_intersects(tsk, mask)) | 72 | ret = mempolicy_nodemask_intersects(tsk, mask); |
| 71 | return true; | ||
| 72 | } else { | 73 | } else { |
| 73 | /* | 74 | /* |
| 74 | * This is not a mempolicy constrained oom, so only | 75 | * This is not a mempolicy constrained oom, so only |
| 75 | * check the mems of tsk's cpuset. | 76 | * check the mems of tsk's cpuset. |
| 76 | */ | 77 | */ |
| 77 | if (cpuset_mems_allowed_intersects(current, tsk)) | 78 | ret = cpuset_mems_allowed_intersects(current, tsk); |
| 78 | return true; | ||
| 79 | } | 79 | } |
| 80 | } while_each_thread(start, tsk); | 80 | if (ret) |
| 81 | break; | ||
| 82 | } | ||
| 83 | rcu_read_unlock(); | ||
| 81 | 84 | ||
| 82 | return false; | 85 | return ret; |
| 83 | } | 86 | } |
| 84 | #else | 87 | #else |
| 85 | static bool has_intersects_mems_allowed(struct task_struct *tsk, | 88 | static bool has_intersects_mems_allowed(struct task_struct *tsk, |
| @@ -97,16 +100,21 @@ static bool has_intersects_mems_allowed(struct task_struct *tsk, | |||
| 97 | */ | 100 | */ |
| 98 | struct task_struct *find_lock_task_mm(struct task_struct *p) | 101 | struct task_struct *find_lock_task_mm(struct task_struct *p) |
| 99 | { | 102 | { |
| 100 | struct task_struct *t = p; | 103 | struct task_struct *t; |
| 101 | 104 | ||
| 102 | do { | 105 | rcu_read_lock(); |
| 106 | |||
| 107 | for_each_thread(p, t) { | ||
| 103 | task_lock(t); | 108 | task_lock(t); |
| 104 | if (likely(t->mm)) | 109 | if (likely(t->mm)) |
| 105 | return t; | 110 | goto found; |
| 106 | task_unlock(t); | 111 | task_unlock(t); |
| 107 | } while_each_thread(p, t); | 112 | } |
| 113 | t = NULL; | ||
| 114 | found: | ||
| 115 | rcu_read_unlock(); | ||
| 108 | 116 | ||
| 109 | return NULL; | 117 | return t; |
| 110 | } | 118 | } |
| 111 | 119 | ||
| 112 | /* return true if the task is not adequate as candidate victim task. */ | 120 | /* return true if the task is not adequate as candidate victim task. */ |
| @@ -301,7 +309,7 @@ static struct task_struct *select_bad_process(unsigned int *ppoints, | |||
| 301 | unsigned long chosen_points = 0; | 309 | unsigned long chosen_points = 0; |
| 302 | 310 | ||
| 303 | rcu_read_lock(); | 311 | rcu_read_lock(); |
| 304 | do_each_thread(g, p) { | 312 | for_each_process_thread(g, p) { |
| 305 | unsigned int points; | 313 | unsigned int points; |
| 306 | 314 | ||
| 307 | switch (oom_scan_process_thread(p, totalpages, nodemask, | 315 | switch (oom_scan_process_thread(p, totalpages, nodemask, |
| @@ -323,7 +331,7 @@ static struct task_struct *select_bad_process(unsigned int *ppoints, | |||
| 323 | chosen = p; | 331 | chosen = p; |
| 324 | chosen_points = points; | 332 | chosen_points = points; |
| 325 | } | 333 | } |
| 326 | } while_each_thread(g, p); | 334 | } |
| 327 | if (chosen) | 335 | if (chosen) |
| 328 | get_task_struct(chosen); | 336 | get_task_struct(chosen); |
| 329 | rcu_read_unlock(); | 337 | rcu_read_unlock(); |
| @@ -406,7 +414,7 @@ void oom_kill_process(struct task_struct *p, gfp_t gfp_mask, int order, | |||
| 406 | { | 414 | { |
| 407 | struct task_struct *victim = p; | 415 | struct task_struct *victim = p; |
| 408 | struct task_struct *child; | 416 | struct task_struct *child; |
| 409 | struct task_struct *t = p; | 417 | struct task_struct *t; |
| 410 | struct mm_struct *mm; | 418 | struct mm_struct *mm; |
| 411 | unsigned int victim_points = 0; | 419 | unsigned int victim_points = 0; |
| 412 | static DEFINE_RATELIMIT_STATE(oom_rs, DEFAULT_RATELIMIT_INTERVAL, | 420 | static DEFINE_RATELIMIT_STATE(oom_rs, DEFAULT_RATELIMIT_INTERVAL, |
| @@ -437,7 +445,7 @@ void oom_kill_process(struct task_struct *p, gfp_t gfp_mask, int order, | |||
| 437 | * still freeing memory. | 445 | * still freeing memory. |
| 438 | */ | 446 | */ |
| 439 | read_lock(&tasklist_lock); | 447 | read_lock(&tasklist_lock); |
| 440 | do { | 448 | for_each_thread(p, t) { |
| 441 | list_for_each_entry(child, &t->children, sibling) { | 449 | list_for_each_entry(child, &t->children, sibling) { |
| 442 | unsigned int child_points; | 450 | unsigned int child_points; |
| 443 | 451 | ||
| @@ -455,13 +463,11 @@ void oom_kill_process(struct task_struct *p, gfp_t gfp_mask, int order, | |||
| 455 | get_task_struct(victim); | 463 | get_task_struct(victim); |
| 456 | } | 464 | } |
| 457 | } | 465 | } |
| 458 | } while_each_thread(p, t); | 466 | } |
| 459 | read_unlock(&tasklist_lock); | 467 | read_unlock(&tasklist_lock); |
| 460 | 468 | ||
| 461 | rcu_read_lock(); | ||
| 462 | p = find_lock_task_mm(victim); | 469 | p = find_lock_task_mm(victim); |
| 463 | if (!p) { | 470 | if (!p) { |
| 464 | rcu_read_unlock(); | ||
| 465 | put_task_struct(victim); | 471 | put_task_struct(victim); |
| 466 | return; | 472 | return; |
| 467 | } else if (victim != p) { | 473 | } else if (victim != p) { |
| @@ -487,6 +493,7 @@ void oom_kill_process(struct task_struct *p, gfp_t gfp_mask, int order, | |||
| 487 | * That thread will now get access to memory reserves since it has a | 493 | * That thread will now get access to memory reserves since it has a |
| 488 | * pending fatal signal. | 494 | * pending fatal signal. |
| 489 | */ | 495 | */ |
| 496 | rcu_read_lock(); | ||
| 490 | for_each_process(p) | 497 | for_each_process(p) |
| 491 | if (p->mm == mm && !same_thread_group(p, victim) && | 498 | if (p->mm == mm && !same_thread_group(p, victim) && |
| 492 | !(p->flags & PF_KTHREAD)) { | 499 | !(p->flags & PF_KTHREAD)) { |
