diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-01-30 08:33:40 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-01-30 08:33:40 -0800 |
commit | a51f67a4b440896dfc170ff3ce35994771b1267f (patch) | |
tree | 66e69f83b63e8517a47e0eb0e7ae730d8a9a109b | |
parent | 0a9626575400879d1d5e6bc8768188b938d7c501 (diff) | |
parent | 181e9bdef37bfcaa41f3ab6c948a2a0d60a268b5 (diff) |
Merge tag 'pm-fix-for-3.3-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
Power management fix for 3.3-rc2
Fix for a hibernate (s2disk) regression introduced during the 3.2
merge window that causes s2disk to trigger BUG_ON() in
freeze_workqueues_begin() if there is not enough swap space to save
the image.
* tag 'pm-fix-for-3.3-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm:
PM / Hibernate: Fix s2disk regression related to freezing workqueues
-rw-r--r-- | include/linux/freezer.h | 2 | ||||
-rw-r--r-- | kernel/power/process.c | 19 | ||||
-rw-r--r-- | kernel/power/user.c | 9 |
3 files changed, 30 insertions, 0 deletions
diff --git a/include/linux/freezer.h b/include/linux/freezer.h index 0ab54e16a91..d09af4b67cf 100644 --- a/include/linux/freezer.h +++ b/include/linux/freezer.h @@ -39,6 +39,7 @@ extern bool __refrigerator(bool check_kthr_stop); extern int freeze_processes(void); extern int freeze_kernel_threads(void); extern void thaw_processes(void); +extern void thaw_kernel_threads(void); static inline bool try_to_freeze(void) { @@ -174,6 +175,7 @@ static inline bool __refrigerator(bool check_kthr_stop) { return false; } static inline int freeze_processes(void) { return -ENOSYS; } static inline int freeze_kernel_threads(void) { return -ENOSYS; } static inline void thaw_processes(void) {} +static inline void thaw_kernel_threads(void) {} static inline bool try_to_freeze(void) { return false; } diff --git a/kernel/power/process.c b/kernel/power/process.c index 77274c9ba2f..eeca00311f3 100644 --- a/kernel/power/process.c +++ b/kernel/power/process.c @@ -188,3 +188,22 @@ void thaw_processes(void) printk("done.\n"); } +void thaw_kernel_threads(void) +{ + struct task_struct *g, *p; + + pm_nosig_freezing = false; + printk("Restarting kernel threads ... "); + + thaw_workqueues(); + + read_lock(&tasklist_lock); + do_each_thread(g, p) { + if (p->flags & (PF_KTHREAD | PF_WQ_WORKER)) + __thaw_task(p); + } while_each_thread(g, p); + read_unlock(&tasklist_lock); + + schedule(); + printk("done.\n"); +} diff --git a/kernel/power/user.c b/kernel/power/user.c index 6b1ab7a8852..e5a21a85730 100644 --- a/kernel/power/user.c +++ b/kernel/power/user.c @@ -274,6 +274,15 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd, swsusp_free(); memset(&data->handle, 0, sizeof(struct snapshot_handle)); data->ready = 0; + /* + * It is necessary to thaw kernel threads here, because + * SNAPSHOT_CREATE_IMAGE may be invoked directly after + * SNAPSHOT_FREE. In that case, if kernel threads were not + * thawed, the preallocation of memory carried out by + * hibernation_snapshot() might run into problems (i.e. it + * might fail or even deadlock). + */ + thaw_kernel_threads(); break; case SNAPSHOT_PREF_IMAGE_SIZE: |