| From 7076202f971b113497daf7a80c26cf16e59ef112 Mon Sep 17 00:00:00 2001 |
| From: "Rafael J. Wysocki" <rjw@sisk.pl> |
| Date: Sun, 29 Jan 2012 20:35:52 +0100 |
| Subject: PM / Hibernate: Fix s2disk regression related to freezing workqueues |
| |
| Commit 2aede851ddf08666f68ffc17be446420e9d2a056 |
| |
| PM / Hibernate: Freeze kernel threads after preallocating memory |
| |
| introduced a mechanism by which kernel threads were frozen after |
| the preallocation of hibernate image memory to avoid problems with |
| frozen kernel threads not responding to memory freeing requests. |
| However, it overlooked the s2disk code path in which the |
| SNAPSHOT_CREATE_IMAGE ioctl was run directly after SNAPSHOT_FREE, |
| which caused freeze_workqueues_begin() to BUG(), because it saw |
| that worqueues had been already frozen. |
| |
| Although in principle this issue might be addressed by removing |
| the relevant BUG_ON() from freeze_workqueues_begin(), that would |
| reintroduce the very problem that commit 2aede851ddf08666f68ffc17be4 |
| attempted to avoid into that particular code path. For this reason, |
| to fix the issue at hand, introduce thaw_kernel_threads() and make |
| the SNAPSHOT_FREE ioctl execute it. |
| |
| Special thanks to Srivatsa S. Bhat for detailed analysis of the |
| problem. |
| |
| Reported-and-tested-by: Jiri Slaby <jslaby@suse.cz> |
| Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> |
| Acked-by: Srivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com> |
| Cc: stable@kernel.org |
| (cherry picked from commit 181e9bdef37bfcaa41f3ab6c948a2a0d60a268b5) |
| |
| Signed-off-by: Simon Horman <horms@verge.net.au> |
| --- |
| include/linux/freezer.h | 2 ++ |
| kernel/power/process.c | 19 +++++++++++++++++++ |
| kernel/power/user.c | 9 +++++++++ |
| 3 files changed, 30 insertions(+) |
| |
| diff --git a/include/linux/freezer.h b/include/linux/freezer.h |
| index b79db3d..a1e0727 100644 |
| --- a/include/linux/freezer.h |
| +++ b/include/linux/freezer.h |
| @@ -44,6 +44,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) |
| { |
| @@ -164,6 +165,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 77274c9..eeca003 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 6b1ab7a..e5a21a8 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: |
| -- |
| 1.7.10.1.362.g242cab3 |
| |