|
@@ -46,13 +46,13 @@ static int try_to_freeze_tasks(bool user_only)
|
|
|
while (true) {
|
|
|
todo = 0;
|
|
|
read_lock(&tasklist_lock);
|
|
|
- do_each_thread(g, p) {
|
|
|
+ for_each_process_thread(g, p) {
|
|
|
if (p == current || !freeze_task(p))
|
|
|
continue;
|
|
|
|
|
|
if (!freezer_should_skip(p))
|
|
|
todo++;
|
|
|
- } while_each_thread(g, p);
|
|
|
+ }
|
|
|
read_unlock(&tasklist_lock);
|
|
|
|
|
|
if (!user_only) {
|
|
@@ -93,11 +93,11 @@ static int try_to_freeze_tasks(bool user_only)
|
|
|
|
|
|
if (!wakeup) {
|
|
|
read_lock(&tasklist_lock);
|
|
|
- do_each_thread(g, p) {
|
|
|
+ for_each_process_thread(g, p) {
|
|
|
if (p != current && !freezer_should_skip(p)
|
|
|
&& freezing(p) && !frozen(p))
|
|
|
sched_show_task(p);
|
|
|
- } while_each_thread(g, p);
|
|
|
+ }
|
|
|
read_unlock(&tasklist_lock);
|
|
|
}
|
|
|
} else {
|
|
@@ -108,6 +108,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
|
|
@@ -118,6 +142,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)
|
|
@@ -132,11 +157,25 @@ int freeze_processes(void)
|
|
|
pm_wakeup_clear();
|
|
|
printk("Freezing user space processes ... ");
|
|
|
pm_freezing = true;
|
|
|
+ oom_kills_saved = oom_kills_count();
|
|
|
error = try_to_freeze_tasks(true);
|
|
|
if (!error) {
|
|
|
- printk("done.");
|
|
|
__usermodehelper_set_disable_depth(UMH_DISABLED);
|
|
|
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);
|
|
|
+ printk("OOM in progress.");
|
|
|
+ error = -EBUSY;
|
|
|
+ } else {
|
|
|
+ printk("done.");
|
|
|
+ }
|
|
|
}
|
|
|
printk("\n");
|
|
|
BUG_ON(in_atomic());
|
|
@@ -191,11 +230,11 @@ void thaw_processes(void)
|
|
|
thaw_workqueues();
|
|
|
|
|
|
read_lock(&tasklist_lock);
|
|
|
- do_each_thread(g, p) {
|
|
|
+ for_each_process_thread(g, p) {
|
|
|
/* No other threads should have PF_SUSPEND_TASK set */
|
|
|
WARN_ON((p != curr) && (p->flags & PF_SUSPEND_TASK));
|
|
|
__thaw_task(p);
|
|
|
- } while_each_thread(g, p);
|
|
|
+ }
|
|
|
read_unlock(&tasklist_lock);
|
|
|
|
|
|
WARN_ON(!(curr->flags & PF_SUSPEND_TASK));
|
|
@@ -218,10 +257,10 @@ void thaw_kernel_threads(void)
|
|
|
thaw_workqueues();
|
|
|
|
|
|
read_lock(&tasklist_lock);
|
|
|
- do_each_thread(g, p) {
|
|
|
+ for_each_process_thread(g, p) {
|
|
|
if (p->flags & (PF_KTHREAD | PF_WQ_WORKER))
|
|
|
__thaw_task(p);
|
|
|
- } while_each_thread(g, p);
|
|
|
+ }
|
|
|
read_unlock(&tasklist_lock);
|
|
|
|
|
|
schedule();
|