]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
PM / Hibernate: Fix s2disk regression related to freezing workqueues
authorRafael J. Wysocki <rjw@sisk.pl>
Sun, 29 Jan 2012 19:35:52 +0000 (20:35 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 13 Feb 2012 19:16:55 +0000 (11:16 -0800)
commit 181e9bdef37bfcaa41f3ab6c948a2a0d60a268b5 upstream.

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>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
include/linux/freezer.h
kernel/power/process.c
kernel/power/user.c

index a5386e3ee756d6c85981b033dc0000deebfa59b7..b5d6b6ad39f5440c92f15082aa6ba349789fd138 100644 (file)
@@ -51,6 +51,7 @@ extern void refrigerator(void);
 extern int freeze_processes(void);
 extern int freeze_kernel_threads(void);
 extern void thaw_processes(void);
+extern void thaw_kernel_threads(void);
 
 static inline int try_to_freeze(void)
 {
@@ -185,6 +186,7 @@ static inline void refrigerator(void) {}
 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 int try_to_freeze(void) { return 0; }
 
index addbbe5531bc42634c78844f5d93796526cb13ec..3d4b9544eebaad5ca3d865e0c2c9de6fd6e2d6fb 100644 (file)
@@ -203,3 +203,12 @@ void thaw_processes(void)
        printk("done.\n");
 }
 
+void thaw_kernel_threads(void)
+{
+       printk("Restarting kernel threads ... ");
+       thaw_workqueues();
+       thaw_tasks(true);
+       schedule();
+       printk("done.\n");
+}
+
index 6d8f535c2b88e11952b3871ecb88d8fa0378ab40..3565b1521c17759df6173a22bcd24c7a7281d61f 100644 (file)
@@ -303,6 +303,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_SET_IMAGE_SIZE: