Skip to content

Commit 7407054

Browse files
Michal Hockotorvalds
authored andcommitted
oom, suspend: fix oom_reaper vs. oom_killer_disable race
Tetsuo has reported the following potential oom_killer_disable vs. oom_reaper race: (1) freeze_processes() starts freezing user space threads. (2) Somebody (maybe a kenrel thread) calls out_of_memory(). (3) The OOM killer calls mark_oom_victim() on a user space thread P1 which is already in __refrigerator(). (4) oom_killer_disable() sets oom_killer_disabled = true. (5) P1 leaves __refrigerator() and enters do_exit(). (6) The OOM reaper calls exit_oom_victim(P1) before P1 can call exit_oom_victim(P1). (7) oom_killer_disable() returns while P1 not yet finished (8) P1 perform IO/interfere with the freezer. This situation is unfortunate. We cannot move oom_killer_disable after all the freezable kernel threads are frozen because the oom victim might depend on some of those kthreads to make a forward progress to exit so we could deadlock. It is also far from trivial to teach the oom_reaper to not call exit_oom_victim() because then we would lose a guarantee of the OOM killer and oom_killer_disable forward progress because exit_mm->mmput might block and never call exit_oom_victim. It seems the easiest way forward is to workaround this race by calling try_to_freeze_tasks again after oom_killer_disable. This will make sure that all the tasks are frozen or it bails out. Fixes: 449d777 ("mm, oom_reaper: clear TIF_MEMDIE for all tasks queued for oom_reaper") Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Michal Hocko <[email protected]> Reported-by: Tetsuo Handa <[email protected]> Cc: "Rafael J. Wysocki" <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent 7186ee0 commit 7407054

File tree

1 file changed

+12
-0
lines changed

1 file changed

+12
-0
lines changed

kernel/power/process.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,18 @@ int freeze_processes(void)
146146
if (!error && !oom_killer_disable())
147147
error = -EBUSY;
148148

149+
/*
150+
* There is a hard to fix race between oom_reaper kernel thread
151+
* and oom_killer_disable. oom_reaper calls exit_oom_victim
152+
* before the victim reaches exit_mm so try to freeze all the tasks
153+
* again and catch such a left over task.
154+
*/
155+
if (!error) {
156+
pr_info("Double checking all user space processes after OOM killer disable... ");
157+
error = try_to_freeze_tasks(true);
158+
pr_cont("\n");
159+
}
160+
149161
if (error)
150162
thaw_processes();
151163
return error;

0 commit comments

Comments
 (0)