diff options
Diffstat (limited to 'kernel/power/process.c')
-rw-r--r-- | kernel/power/process.c | 40 |
1 files changed, 39 insertions, 1 deletions
diff --git a/kernel/power/process.c b/kernel/power/process.c index 7b323221b9ee..5cc588c1abab 100644 --- a/kernel/power/process.c +++ b/kernel/power/process.c | |||
@@ -108,6 +108,28 @@ static int try_to_freeze_tasks(bool user_only) | |||
108 | return todo ? -EBUSY : 0; | 108 | return todo ? -EBUSY : 0; |
109 | } | 109 | } |
110 | 110 | ||
111 | /* | ||
112 | * Returns true if all freezable tasks (except for current) are frozen already | ||
113 | */ | ||
114 | static bool check_frozen_processes(void) | ||
115 | { | ||
116 | struct task_struct *g, *p; | ||
117 | bool ret = true; | ||
118 | |||
119 | read_lock(&tasklist_lock); | ||
120 | for_each_process_thread(g, p) { | ||
121 | if (p != current && !freezer_should_skip(p) && | ||
122 | !frozen(p)) { | ||
123 | ret = false; | ||
124 | goto done; | ||
125 | } | ||
126 | } | ||
127 | done: | ||
128 | read_unlock(&tasklist_lock); | ||
129 | |||
130 | return ret; | ||
131 | } | ||
132 | |||
111 | /** | 133 | /** |
112 | * freeze_processes - Signal user space processes to enter the refrigerator. | 134 | * freeze_processes - Signal user space processes to enter the refrigerator. |
113 | * The current thread will not be frozen. The same process that calls | 135 | * 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) | |||
118 | int freeze_processes(void) | 140 | int freeze_processes(void) |
119 | { | 141 | { |
120 | int error; | 142 | int error; |
143 | int oom_kills_saved; | ||
121 | 144 | ||
122 | error = __usermodehelper_disable(UMH_FREEZING); | 145 | error = __usermodehelper_disable(UMH_FREEZING); |
123 | if (error) | 146 | if (error) |
@@ -132,12 +155,27 @@ int freeze_processes(void) | |||
132 | pm_wakeup_clear(); | 155 | pm_wakeup_clear(); |
133 | printk("Freezing user space processes ... "); | 156 | printk("Freezing user space processes ... "); |
134 | pm_freezing = true; | 157 | pm_freezing = true; |
158 | oom_kills_saved = oom_kills_count(); | ||
135 | error = try_to_freeze_tasks(true); | 159 | error = try_to_freeze_tasks(true); |
136 | if (!error) { | 160 | if (!error) { |
137 | printk("done."); | ||
138 | __usermodehelper_set_disable_depth(UMH_DISABLED); | 161 | __usermodehelper_set_disable_depth(UMH_DISABLED); |
139 | oom_killer_disable(); | 162 | oom_killer_disable(); |
163 | |||
164 | /* | ||
165 | * There might have been an OOM kill while we were | ||
166 | * freezing tasks and the killed task might be still | ||
167 | * on the way out so we have to double check for race. | ||
168 | */ | ||
169 | if (oom_kills_count() != oom_kills_saved && | ||
170 | !check_frozen_processes()) { | ||
171 | __usermodehelper_set_disable_depth(UMH_ENABLED); | ||
172 | printk("OOM in progress."); | ||
173 | error = -EBUSY; | ||
174 | goto done; | ||
175 | } | ||
176 | printk("done."); | ||
140 | } | 177 | } |
178 | done: | ||
141 | printk("\n"); | 179 | printk("\n"); |
142 | BUG_ON(in_atomic()); | 180 | BUG_ON(in_atomic()); |
143 | 181 | ||