diff options
Diffstat (limited to 'kernel/power')
| -rw-r--r-- | kernel/power/process.c | 50 |
1 files changed, 41 insertions, 9 deletions
diff --git a/kernel/power/process.c b/kernel/power/process.c index 899e07479..3bd3a1185 100644 --- a/kernel/power/process.c +++ b/kernel/power/process.c @@ -118,6 +118,30 @@ static int try_to_freeze_tasks(bool user_only) return todo ? -EBUSY : 0; } +static bool __check_frozen_processes(void) +{ + struct task_struct *g, *p; + + for_each_process_thread(g, p) + if (p != current && !freezer_should_skip(p) && !frozen(p)) + return false; + + return true; +} + +/* + * Returns true if all freezable tasks (except for current) are frozen already + */ +static bool check_frozen_processes(void) +{ + bool ret; + + read_lock(&tasklist_lock); + ret = __check_frozen_processes(); + read_unlock(&tasklist_lock); + return ret; +} + /** * freeze_processes - Signal user space processes to enter the refrigerator. * The current thread will not be frozen. The same process that calls @@ -128,6 +152,7 @@ static int try_to_freeze_tasks(bool user_only) int freeze_processes(void) { int error; + int oom_kills_saved; error = __usermodehelper_disable(UMH_FREEZING); if (error) @@ -142,22 +167,29 @@ int freeze_processes(void) pm_wakeup_clear(); pr_info("Freezing user space processes ... "); pm_freezing = true; + oom_kills_saved = oom_kills_count(); error = try_to_freeze_tasks(true); if (!error) { __usermodehelper_set_disable_depth(UMH_DISABLED); - pr_cont("done."); + oom_killer_disable(); + + /* + * There might have been an OOM kill while we were + * freezing tasks and the killed task might be still + * on the way out so we have to double check for race. + */ + if (oom_kills_count() != oom_kills_saved && + !check_frozen_processes()) { + __usermodehelper_set_disable_depth(UMH_ENABLED); + pr_cont("OOM in progress."); + error = -EBUSY; + } else { + pr_cont("done."); + } } pr_cont("\n"); BUG_ON(in_atomic()); - /* - * Now that the whole userspace is frozen we need to disbale - * the OOM killer to disallow any further interference with - * killable tasks. - */ - if (!error && !oom_killer_disable()) - error = -EBUSY; - if (error) thaw_processes(); return error; |
