diff options
Diffstat (limited to 'kernel/power')
| -rw-r--r-- | kernel/power/power.h | 24 | ||||
| -rw-r--r-- | kernel/power/process.c | 26 | ||||
| -rw-r--r-- | kernel/power/snapshot.c | 3 | ||||
| -rw-r--r-- | kernel/power/user.c | 15 |
4 files changed, 61 insertions, 7 deletions
diff --git a/kernel/power/power.h b/kernel/power/power.h index 0c4defe6d3b8..21724eee5206 100644 --- a/kernel/power/power.h +++ b/kernel/power/power.h | |||
| @@ -231,8 +231,28 @@ extern int pm_test_level; | |||
| 231 | #ifdef CONFIG_SUSPEND_FREEZER | 231 | #ifdef CONFIG_SUSPEND_FREEZER |
| 232 | static inline int suspend_freeze_processes(void) | 232 | static inline int suspend_freeze_processes(void) |
| 233 | { | 233 | { |
| 234 | int error = freeze_processes(); | 234 | int error; |
| 235 | return error ? : freeze_kernel_threads(); | 235 | |
| 236 | error = freeze_processes(); | ||
| 237 | |||
| 238 | /* | ||
| 239 | * freeze_processes() automatically thaws every task if freezing | ||
| 240 | * fails. So we need not do anything extra upon error. | ||
| 241 | */ | ||
| 242 | if (error) | ||
| 243 | goto Finish; | ||
| 244 | |||
| 245 | error = freeze_kernel_threads(); | ||
| 246 | |||
| 247 | /* | ||
| 248 | * freeze_kernel_threads() thaws only kernel threads upon freezing | ||
| 249 | * failure. So we have to thaw the userspace tasks ourselves. | ||
| 250 | */ | ||
| 251 | if (error) | ||
| 252 | thaw_processes(); | ||
| 253 | |||
| 254 | Finish: | ||
| 255 | return error; | ||
| 236 | } | 256 | } |
| 237 | 257 | ||
| 238 | static inline void suspend_thaw_processes(void) | 258 | static inline void suspend_thaw_processes(void) |
diff --git a/kernel/power/process.c b/kernel/power/process.c index 77274c9ba2f1..7e426459e60a 100644 --- a/kernel/power/process.c +++ b/kernel/power/process.c | |||
| @@ -143,7 +143,10 @@ int freeze_processes(void) | |||
| 143 | /** | 143 | /** |
| 144 | * freeze_kernel_threads - Make freezable kernel threads go to the refrigerator. | 144 | * freeze_kernel_threads - Make freezable kernel threads go to the refrigerator. |
| 145 | * | 145 | * |
| 146 | * On success, returns 0. On failure, -errno and system is fully thawed. | 146 | * On success, returns 0. On failure, -errno and only the kernel threads are |
| 147 | * thawed, so as to give a chance to the caller to do additional cleanups | ||
| 148 | * (if any) before thawing the userspace tasks. So, it is the responsibility | ||
| 149 | * of the caller to thaw the userspace tasks, when the time is right. | ||
| 147 | */ | 150 | */ |
| 148 | int freeze_kernel_threads(void) | 151 | int freeze_kernel_threads(void) |
| 149 | { | 152 | { |
| @@ -159,7 +162,7 @@ int freeze_kernel_threads(void) | |||
| 159 | BUG_ON(in_atomic()); | 162 | BUG_ON(in_atomic()); |
| 160 | 163 | ||
| 161 | if (error) | 164 | if (error) |
| 162 | thaw_processes(); | 165 | thaw_kernel_threads(); |
| 163 | return error; | 166 | return error; |
| 164 | } | 167 | } |
| 165 | 168 | ||
| @@ -188,3 +191,22 @@ void thaw_processes(void) | |||
| 188 | printk("done.\n"); | 191 | printk("done.\n"); |
| 189 | } | 192 | } |
| 190 | 193 | ||
| 194 | void thaw_kernel_threads(void) | ||
| 195 | { | ||
| 196 | struct task_struct *g, *p; | ||
| 197 | |||
| 198 | pm_nosig_freezing = false; | ||
| 199 | printk("Restarting kernel threads ... "); | ||
| 200 | |||
| 201 | thaw_workqueues(); | ||
| 202 | |||
| 203 | read_lock(&tasklist_lock); | ||
| 204 | do_each_thread(g, p) { | ||
| 205 | if (p->flags & (PF_KTHREAD | PF_WQ_WORKER)) | ||
| 206 | __thaw_task(p); | ||
| 207 | } while_each_thread(g, p); | ||
| 208 | read_unlock(&tasklist_lock); | ||
| 209 | |||
| 210 | schedule(); | ||
| 211 | printk("done.\n"); | ||
| 212 | } | ||
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c index 1cf88900ec4f..6a768e537001 100644 --- a/kernel/power/snapshot.c +++ b/kernel/power/snapshot.c | |||
| @@ -812,7 +812,8 @@ unsigned int snapshot_additional_pages(struct zone *zone) | |||
| 812 | unsigned int res; | 812 | unsigned int res; |
| 813 | 813 | ||
| 814 | res = DIV_ROUND_UP(zone->spanned_pages, BM_BITS_PER_BLOCK); | 814 | res = DIV_ROUND_UP(zone->spanned_pages, BM_BITS_PER_BLOCK); |
| 815 | res += DIV_ROUND_UP(res * sizeof(struct bm_block), PAGE_SIZE); | 815 | res += DIV_ROUND_UP(res * sizeof(struct bm_block), |
| 816 | LINKED_PAGE_DATA_SIZE); | ||
| 816 | return 2 * res; | 817 | return 2 * res; |
| 817 | } | 818 | } |
| 818 | 819 | ||
diff --git a/kernel/power/user.c b/kernel/power/user.c index 6b1ab7a88522..3e100075b13c 100644 --- a/kernel/power/user.c +++ b/kernel/power/user.c | |||
| @@ -249,13 +249,15 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd, | |||
| 249 | } | 249 | } |
| 250 | pm_restore_gfp_mask(); | 250 | pm_restore_gfp_mask(); |
| 251 | error = hibernation_snapshot(data->platform_support); | 251 | error = hibernation_snapshot(data->platform_support); |
| 252 | if (!error) { | 252 | if (error) { |
| 253 | thaw_kernel_threads(); | ||
| 254 | } else { | ||
| 253 | error = put_user(in_suspend, (int __user *)arg); | 255 | error = put_user(in_suspend, (int __user *)arg); |
| 254 | if (!error && !freezer_test_done) | 256 | if (!error && !freezer_test_done) |
| 255 | data->ready = 1; | 257 | data->ready = 1; |
| 256 | if (freezer_test_done) { | 258 | if (freezer_test_done) { |
| 257 | freezer_test_done = false; | 259 | freezer_test_done = false; |
| 258 | thaw_processes(); | 260 | thaw_kernel_threads(); |
| 259 | } | 261 | } |
| 260 | } | 262 | } |
| 261 | break; | 263 | break; |
| @@ -274,6 +276,15 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd, | |||
| 274 | swsusp_free(); | 276 | swsusp_free(); |
| 275 | memset(&data->handle, 0, sizeof(struct snapshot_handle)); | 277 | memset(&data->handle, 0, sizeof(struct snapshot_handle)); |
| 276 | data->ready = 0; | 278 | data->ready = 0; |
| 279 | /* | ||
| 280 | * It is necessary to thaw kernel threads here, because | ||
| 281 | * SNAPSHOT_CREATE_IMAGE may be invoked directly after | ||
| 282 | * SNAPSHOT_FREE. In that case, if kernel threads were not | ||
| 283 | * thawed, the preallocation of memory carried out by | ||
| 284 | * hibernation_snapshot() might run into problems (i.e. it | ||
| 285 | * might fail or even deadlock). | ||
| 286 | */ | ||
| 287 | thaw_kernel_threads(); | ||
| 277 | break; | 288 | break; |
| 278 | 289 | ||
| 279 | case SNAPSHOT_PREF_IMAGE_SIZE: | 290 | case SNAPSHOT_PREF_IMAGE_SIZE: |
