aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/power
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2011-09-26 14:32:27 -0400
committerRafael J. Wysocki <rjw@sisk.pl>2011-10-16 17:28:52 -0400
commit2aede851ddf08666f68ffc17be446420e9d2a056 (patch)
treef63a0477c9fe618cd374065bac4cb5f172aaf7db /kernel/power
parent8f88893c05f2f677f18f2ce5591b4bed5d4a7535 (diff)
PM / Hibernate: Freeze kernel threads after preallocating memory
There is a problem with the current ordering of hibernate code which leads to deadlocks in some filesystems' memory shrinkers. Namely, some filesystems use freezable kernel threads that are inactive when the hibernate memory preallocation is carried out. Those same filesystems use memory shrinkers that may be triggered by the hibernate memory preallocation. If those memory shrinkers wait for the frozen kernel threads, the hibernate process deadlocks (this happens with XFS, for one example). Apparently, it is not technically viable to redesign the filesystems in question to avoid the situation described above, so the only possible solution of this issue is to defer the freezing of kernel threads until the hibernate memory preallocation is done, which is implemented by this change. Unfortunately, this requires the memory preallocation to be done before the "prepare" stage of device freeze, so after this change the only way drivers can allocate additional memory for their freeze routines in a clean way is to use PM notifiers. Reported-by: Christoph <cr2005@u-club.de> Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Diffstat (limited to 'kernel/power')
-rw-r--r--kernel/power/hibernate.c12
-rw-r--r--kernel/power/power.h3
-rw-r--r--kernel/power/process.c30
3 files changed, 30 insertions, 15 deletions
diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c
index 8f7b1db1ece1..3a20466015f8 100644
--- a/kernel/power/hibernate.c
+++ b/kernel/power/hibernate.c
@@ -334,13 +334,17 @@ int hibernation_snapshot(int platform_mode)
334 if (error) 334 if (error)
335 goto Close; 335 goto Close;
336 336
337 error = dpm_prepare(PMSG_FREEZE);
338 if (error)
339 goto Complete_devices;
340
341 /* Preallocate image memory before shutting down devices. */ 337 /* Preallocate image memory before shutting down devices. */
342 error = hibernate_preallocate_memory(); 338 error = hibernate_preallocate_memory();
343 if (error) 339 if (error)
340 goto Close;
341
342 error = freeze_kernel_threads();
343 if (error)
344 goto Close;
345
346 error = dpm_prepare(PMSG_FREEZE);
347 if (error)
344 goto Complete_devices; 348 goto Complete_devices;
345 349
346 suspend_console(); 350 suspend_console();
diff --git a/kernel/power/power.h b/kernel/power/power.h
index 9a00a0a26280..e6206397ce67 100644
--- a/kernel/power/power.h
+++ b/kernel/power/power.h
@@ -228,7 +228,8 @@ extern int pm_test_level;
228#ifdef CONFIG_SUSPEND_FREEZER 228#ifdef CONFIG_SUSPEND_FREEZER
229static inline int suspend_freeze_processes(void) 229static inline int suspend_freeze_processes(void)
230{ 230{
231 return freeze_processes(); 231 int error = freeze_processes();
232 return error ? : freeze_kernel_threads();
232} 233}
233 234
234static inline void suspend_thaw_processes(void) 235static inline void suspend_thaw_processes(void)
diff --git a/kernel/power/process.c b/kernel/power/process.c
index 0cf3a27a6c9d..addbbe5531bc 100644
--- a/kernel/power/process.c
+++ b/kernel/power/process.c
@@ -135,7 +135,7 @@ static int try_to_freeze_tasks(bool sig_only)
135} 135}
136 136
137/** 137/**
138 * freeze_processes - tell processes to enter the refrigerator 138 * freeze_processes - Signal user space processes to enter the refrigerator.
139 */ 139 */
140int freeze_processes(void) 140int freeze_processes(void)
141{ 141{
@@ -143,20 +143,30 @@ int freeze_processes(void)
143 143
144 printk("Freezing user space processes ... "); 144 printk("Freezing user space processes ... ");
145 error = try_to_freeze_tasks(true); 145 error = try_to_freeze_tasks(true);
146 if (error) 146 if (!error) {
147 goto Exit; 147 printk("done.");
148 printk("done.\n"); 148 oom_killer_disable();
149 }
150 printk("\n");
151 BUG_ON(in_atomic());
152
153 return error;
154}
155
156/**
157 * freeze_kernel_threads - Make freezable kernel threads go to the refrigerator.
158 */
159int freeze_kernel_threads(void)
160{
161 int error;
149 162
150 printk("Freezing remaining freezable tasks ... "); 163 printk("Freezing remaining freezable tasks ... ");
151 error = try_to_freeze_tasks(false); 164 error = try_to_freeze_tasks(false);
152 if (error) 165 if (!error)
153 goto Exit; 166 printk("done.");
154 printk("done.");
155 167
156 oom_killer_disable();
157 Exit:
158 BUG_ON(in_atomic());
159 printk("\n"); 168 printk("\n");
169 BUG_ON(in_atomic());
160 170
161 return error; 171 return error;
162} 172}