OSDN Git Service

PM: convert do_each_thread to for_each_process_thread
[uclinux-h8/linux.git] / kernel / power / process.c
index 7b32322..7f0d434 100644 (file)
@@ -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,28 @@ static int try_to_freeze_tasks(bool user_only)
        return todo ? -EBUSY : 0;
 }
 
+/*
+ * Returns true if all freezable tasks (except for current) are frozen already
+ */
+static bool check_frozen_processes(void)
+{
+       struct task_struct *g, *p;
+       bool ret = true;
+
+       read_lock(&tasklist_lock);
+       for_each_process_thread(g, p) {
+               if (p != current && !freezer_should_skip(p) &&
+                   !frozen(p)) {
+                       ret = false;
+                       goto done;
+               }
+       }
+done:
+       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 +140,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,12 +155,27 @@ 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;
+                       goto done;
+               }
+               printk("done.");
        }
+done:
        printk("\n");
        BUG_ON(in_atomic());
 
@@ -191,11 +229,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 +256,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();