Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * drivers/power/process.c - Functions for starting/stopping processes on | |
3 | * suspend transitions. | |
4 | * | |
5 | * Originally from swsusp. | |
6 | */ | |
7 | ||
8 | ||
9 | #undef DEBUG | |
10 | ||
1da177e4 | 11 | #include <linux/interrupt.h> |
1a8670a2 | 12 | #include <linux/oom.h> |
1da177e4 LT |
13 | #include <linux/suspend.h> |
14 | #include <linux/module.h> | |
02aaeb9b | 15 | #include <linux/syscalls.h> |
7dfb7103 | 16 | #include <linux/freezer.h> |
be404f02 | 17 | #include <linux/delay.h> |
a0a1a5fd | 18 | #include <linux/workqueue.h> |
1e73203c | 19 | #include <linux/kmod.h> |
1da177e4 LT |
20 | |
21 | /* | |
22 | * Timeout for stopping processes | |
23 | */ | |
957d1282 | 24 | unsigned int __read_mostly freeze_timeout_msecs = 20 * MSEC_PER_SEC; |
1da177e4 | 25 | |
839e3407 | 26 | static int try_to_freeze_tasks(bool user_only) |
1da177e4 | 27 | { |
1da177e4 | 28 | struct task_struct *g, *p; |
11b2ce2b RW |
29 | unsigned long end_time; |
30 | unsigned int todo; | |
a0a1a5fd | 31 | bool wq_busy = false; |
438e2ce6 | 32 | struct timeval start, end; |
6fa3eb70 S |
33 | u64 elapsed_msecs64; |
34 | unsigned int elapsed_msecs; | |
dbeeec5f | 35 | bool wakeup = false; |
6fa3eb70 | 36 | int sleep_usecs = USEC_PER_MSEC; |
438e2ce6 RW |
37 | |
38 | do_gettimeofday(&start); | |
3e1d1d28 | 39 | |
957d1282 | 40 | end_time = jiffies + msecs_to_jiffies(freeze_timeout_msecs); |
a0a1a5fd | 41 | |
839e3407 | 42 | if (!user_only) |
a0a1a5fd TH |
43 | freeze_workqueues_begin(); |
44 | ||
be404f02 | 45 | while (true) { |
11b2ce2b | 46 | todo = 0; |
1da177e4 LT |
47 | read_lock(&tasklist_lock); |
48 | do_each_thread(g, p) { | |
839e3407 | 49 | if (p == current || !freeze_task(p)) |
d5d8c597 RW |
50 | continue; |
51 | ||
5d8f72b5 | 52 | if (!freezer_should_skip(p)) |
ba96a0c8 | 53 | todo++; |
1da177e4 LT |
54 | } while_each_thread(g, p); |
55 | read_unlock(&tasklist_lock); | |
a0a1a5fd | 56 | |
839e3407 | 57 | if (!user_only) { |
a0a1a5fd TH |
58 | wq_busy = freeze_workqueues_busy(); |
59 | todo += wq_busy; | |
60 | } | |
61 | ||
be404f02 | 62 | if (!todo || time_after(jiffies, end_time)) |
6161b2ce | 63 | break; |
be404f02 | 64 | |
a2867e08 | 65 | if (pm_wakeup_pending()) { |
dbeeec5f RW |
66 | wakeup = true; |
67 | break; | |
68 | } | |
69 | ||
be404f02 TH |
70 | /* |
71 | * We need to retry, but first give the freezing tasks some | |
6fa3eb70 S |
72 | * time to enter the refrigerator. Start with an initial |
73 | * 1 ms sleep followed by exponential backoff until 8 ms. | |
be404f02 | 74 | */ |
6fa3eb70 S |
75 | usleep_range(sleep_usecs / 2, sleep_usecs); |
76 | if (sleep_usecs < 8 * USEC_PER_MSEC) | |
77 | sleep_usecs *= 2; | |
be404f02 | 78 | } |
3e1d1d28 | 79 | |
438e2ce6 | 80 | do_gettimeofday(&end); |
6fa3eb70 S |
81 | elapsed_msecs64 = timeval_to_ns(&end) - timeval_to_ns(&start); |
82 | do_div(elapsed_msecs64, NSEC_PER_MSEC); | |
83 | elapsed_msecs = elapsed_msecs64; | |
438e2ce6 | 84 | |
6161b2ce | 85 | if (todo) { |
14b5b7cf | 86 | printk("\n"); |
6fa3eb70 | 87 | printk(KERN_ERR "Freezing of tasks %s after %d.%03d seconds " |
a0a1a5fd | 88 | "(%d tasks refusing to freeze, wq_busy=%d):\n", |
dbeeec5f | 89 | wakeup ? "aborted" : "failed", |
6fa3eb70 | 90 | elapsed_msecs / 1000, elapsed_msecs % 1000, |
a0a1a5fd TH |
91 | todo - wq_busy, wq_busy); |
92 | ||
6c83b481 RW |
93 | if (!wakeup) { |
94 | read_lock(&tasklist_lock); | |
95 | do_each_thread(g, p) { | |
96 | if (p != current && !freezer_should_skip(p) | |
97 | && freezing(p) && !frozen(p)) | |
98 | sched_show_task(p); | |
99 | } while_each_thread(g, p); | |
100 | read_unlock(&tasklist_lock); | |
101 | } | |
438e2ce6 | 102 | } else { |
6fa3eb70 S |
103 | printk("(elapsed %d.%03d seconds) ", elapsed_msecs / 1000, |
104 | elapsed_msecs % 1000); | |
6161b2ce PM |
105 | } |
106 | ||
e7cd8a72 | 107 | return todo ? -EBUSY : 0; |
11b2ce2b RW |
108 | } |
109 | ||
e033782a MH |
110 | /* |
111 | * Returns true if all freezable tasks (except for current) are frozen already | |
112 | */ | |
113 | static bool check_frozen_processes(void) | |
114 | { | |
115 | struct task_struct *g, *p; | |
116 | bool ret = true; | |
117 | ||
118 | read_lock(&tasklist_lock); | |
119 | for_each_process_thread(g, p) { | |
120 | if (p != current && !freezer_should_skip(p) && | |
121 | !frozen(p)) { | |
122 | ret = false; | |
123 | goto done; | |
124 | } | |
125 | } | |
126 | done: | |
127 | read_unlock(&tasklist_lock); | |
128 | ||
129 | return ret; | |
130 | } | |
131 | ||
11b2ce2b | 132 | /** |
2aede851 | 133 | * freeze_processes - Signal user space processes to enter the refrigerator. |
03afed8b TH |
134 | * |
135 | * On success, returns 0. On failure, -errno and system is fully thawed. | |
11b2ce2b RW |
136 | */ |
137 | int freeze_processes(void) | |
138 | { | |
e7cd8a72 | 139 | int error; |
e033782a | 140 | int oom_kills_saved; |
11b2ce2b | 141 | |
247bc037 | 142 | error = __usermodehelper_disable(UMH_FREEZING); |
1e73203c RW |
143 | if (error) |
144 | return error; | |
145 | ||
a3201227 TH |
146 | if (!pm_freezing) |
147 | atomic_inc(&system_freezing_cnt); | |
148 | ||
b842ee57 | 149 | printk("Freezing user space processes ... "); |
a3201227 | 150 | pm_freezing = true; |
e033782a | 151 | oom_kills_saved = oom_kills_count(); |
ebb12db5 | 152 | error = try_to_freeze_tasks(true); |
2aede851 | 153 | if (!error) { |
247bc037 | 154 | __usermodehelper_set_disable_depth(UMH_DISABLED); |
2aede851 | 155 | oom_killer_disable(); |
e033782a MH |
156 | |
157 | /* | |
158 | * There might have been an OOM kill while we were | |
159 | * freezing tasks and the killed task might be still | |
160 | * on the way out so we have to double check for race. | |
161 | */ | |
162 | if (oom_kills_count() != oom_kills_saved && | |
163 | !check_frozen_processes()) { | |
164 | __usermodehelper_set_disable_depth(UMH_ENABLED); | |
165 | printk("OOM in progress."); | |
166 | error = -EBUSY; | |
167 | goto done; | |
168 | } | |
169 | printk("done."); | |
2aede851 | 170 | } |
e033782a | 171 | done: |
2aede851 RW |
172 | printk("\n"); |
173 | BUG_ON(in_atomic()); | |
174 | ||
03afed8b TH |
175 | if (error) |
176 | thaw_processes(); | |
2aede851 RW |
177 | return error; |
178 | } | |
6fa3eb70 | 179 | EXPORT_SYMBOL_GPL(freeze_processes); |
2aede851 RW |
180 | |
181 | /** | |
182 | * freeze_kernel_threads - Make freezable kernel threads go to the refrigerator. | |
03afed8b | 183 | * |
379e0be8 SB |
184 | * On success, returns 0. On failure, -errno and only the kernel threads are |
185 | * thawed, so as to give a chance to the caller to do additional cleanups | |
186 | * (if any) before thawing the userspace tasks. So, it is the responsibility | |
187 | * of the caller to thaw the userspace tasks, when the time is right. | |
2aede851 RW |
188 | */ |
189 | int freeze_kernel_threads(void) | |
190 | { | |
191 | int error; | |
11b2ce2b | 192 | |
b842ee57 | 193 | printk("Freezing remaining freezable tasks ... "); |
a3201227 | 194 | pm_nosig_freezing = true; |
ebb12db5 | 195 | error = try_to_freeze_tasks(false); |
2aede851 RW |
196 | if (!error) |
197 | printk("done."); | |
7f33d49a | 198 | |
b842ee57 | 199 | printk("\n"); |
2aede851 | 200 | BUG_ON(in_atomic()); |
7f33d49a | 201 | |
03afed8b | 202 | if (error) |
379e0be8 | 203 | thaw_kernel_threads(); |
b842ee57 | 204 | return error; |
1da177e4 | 205 | } |
6fa3eb70 | 206 | EXPORT_SYMBOL_GPL(freeze_kernel_threads); |
1da177e4 | 207 | |
6cd8dedc | 208 | void thaw_processes(void) |
1da177e4 LT |
209 | { |
210 | struct task_struct *g, *p; | |
211 | ||
a3201227 TH |
212 | if (pm_freezing) |
213 | atomic_dec(&system_freezing_cnt); | |
214 | pm_freezing = false; | |
215 | pm_nosig_freezing = false; | |
216 | ||
6cd8dedc TH |
217 | oom_killer_enable(); |
218 | ||
219 | printk("Restarting tasks ... "); | |
220 | ||
804536e8 | 221 | __usermodehelper_set_disable_depth(UMH_FREEZING); |
6cd8dedc TH |
222 | thaw_workqueues(); |
223 | ||
1da177e4 | 224 | read_lock(&tasklist_lock); |
a9b6f562 | 225 | do_each_thread(g, p) { |
6fa3eb70 | 226 | BUG_ON(!virt_addr_valid(next_task(g))); |
a5be2d0d | 227 | __thaw_task(p); |
a9b6f562 | 228 | } while_each_thread(g, p); |
1da177e4 | 229 | read_unlock(&tasklist_lock); |
7f33d49a | 230 | |
1e73203c RW |
231 | usermodehelper_enable(); |
232 | ||
1da177e4 | 233 | schedule(); |
14b5b7cf | 234 | printk("done.\n"); |
1da177e4 | 235 | } |
6fa3eb70 | 236 | EXPORT_SYMBOL_GPL(thaw_processes); |
1da177e4 | 237 | |
181e9bde RW |
238 | void thaw_kernel_threads(void) |
239 | { | |
240 | struct task_struct *g, *p; | |
241 | ||
242 | pm_nosig_freezing = false; | |
243 | printk("Restarting kernel threads ... "); | |
244 | ||
245 | thaw_workqueues(); | |
246 | ||
247 | read_lock(&tasklist_lock); | |
248 | do_each_thread(g, p) { | |
249 | if (p->flags & (PF_KTHREAD | PF_WQ_WORKER)) | |
250 | __thaw_task(p); | |
251 | } while_each_thread(g, p); | |
252 | read_unlock(&tasklist_lock); | |
253 | ||
254 | schedule(); | |
255 | printk("done.\n"); | |
256 | } | |
6fa3eb70 | 257 | EXPORT_SYMBOL_GPL(thaw_kernel_threads); |