diff options
Diffstat (limited to 'mm/oom_kill.c')
-rw-r--r-- | mm/oom_kill.c | 12 |
1 files changed, 10 insertions, 2 deletions
diff --git a/mm/oom_kill.c b/mm/oom_kill.c index f0e8cd9edb1a..26ea8636758f 100644 --- a/mm/oom_kill.c +++ b/mm/oom_kill.c | |||
@@ -647,8 +647,8 @@ static int oom_reaper(void *unused) | |||
647 | 647 | ||
648 | static void wake_oom_reaper(struct task_struct *tsk) | 648 | static void wake_oom_reaper(struct task_struct *tsk) |
649 | { | 649 | { |
650 | /* tsk is already queued? */ | 650 | /* mm is already queued? */ |
651 | if (tsk == oom_reaper_list || tsk->oom_reaper_list) | 651 | if (test_and_set_bit(MMF_OOM_REAP_QUEUED, &tsk->signal->oom_mm->flags)) |
652 | return; | 652 | return; |
653 | 653 | ||
654 | get_task_struct(tsk); | 654 | get_task_struct(tsk); |
@@ -975,6 +975,13 @@ static void oom_kill_process(struct oom_control *oc, const char *message) | |||
975 | * still freeing memory. | 975 | * still freeing memory. |
976 | */ | 976 | */ |
977 | read_lock(&tasklist_lock); | 977 | read_lock(&tasklist_lock); |
978 | |||
979 | /* | ||
980 | * The task 'p' might have already exited before reaching here. The | ||
981 | * put_task_struct() will free task_struct 'p' while the loop still try | ||
982 | * to access the field of 'p', so, get an extra reference. | ||
983 | */ | ||
984 | get_task_struct(p); | ||
978 | for_each_thread(p, t) { | 985 | for_each_thread(p, t) { |
979 | list_for_each_entry(child, &t->children, sibling) { | 986 | list_for_each_entry(child, &t->children, sibling) { |
980 | unsigned int child_points; | 987 | unsigned int child_points; |
@@ -994,6 +1001,7 @@ static void oom_kill_process(struct oom_control *oc, const char *message) | |||
994 | } | 1001 | } |
995 | } | 1002 | } |
996 | } | 1003 | } |
1004 | put_task_struct(p); | ||
997 | read_unlock(&tasklist_lock); | 1005 | read_unlock(&tasklist_lock); |
998 | 1006 | ||
999 | /* | 1007 | /* |