aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/power
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2011-05-17 17:26:00 -0400
committerRafael J. Wysocki <rjw@sisk.pl>2011-05-17 17:26:00 -0400
commit91e7c75ba93c48a82670d630b9daac92ff70095d (patch)
treeb44ac3dca1d03cce99cccc3f4ce55d4b5475d373 /kernel/power
parentc650da23d59d2c82307380414606774c6d49b8bd (diff)
PM: Allow drivers to allocate memory from .prepare() callbacks safely
If device drivers allocate substantial amounts of memory (above 1 MB) in their hibernate .freeze() callbacks (or in their legacy suspend callbcks during hibernation), the subsequent creation of hibernate image may fail due to the lack of memory. This is the case, because the drivers' .freeze() callbacks are executed after the hibernate memory preallocation has been carried out and the preallocated amount of memory may be too small to cover the new driver allocations. Unfortunately, the drivers' .prepare() callbacks also are executed after the hibernate memory preallocation has completed, so they are not suitable for allocating additional memory either. Thus the only way a driver can safely allocate memory during hibernation is to use a hibernate/suspend notifier. However, the notifiers are called before the freezing of user space and the drivers wanting to use them for allocating additional memory may not know how much memory needs to be allocated at that point. To let device drivers overcome this difficulty rework the hibernation sequence so that the memory preallocation is carried out after the drivers' .prepare() callbacks have been executed, so that the .prepare() callbacks can be used for allocating additional memory to be used by the drivers' .freeze() callbacks. Update documentation to match the new behavior of the code. Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Diffstat (limited to 'kernel/power')
-rw-r--r--kernel/power/hibernate.c17
1 files changed, 13 insertions, 4 deletions
diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c
index 95a2ac40f48c..f9bec56d8825 100644
--- a/kernel/power/hibernate.c
+++ b/kernel/power/hibernate.c
@@ -327,20 +327,25 @@ static int create_image(int platform_mode)
327 327
328int hibernation_snapshot(int platform_mode) 328int hibernation_snapshot(int platform_mode)
329{ 329{
330 pm_message_t msg = PMSG_RECOVER;
330 int error; 331 int error;
331 332
332 error = platform_begin(platform_mode); 333 error = platform_begin(platform_mode);
333 if (error) 334 if (error)
334 goto Close; 335 goto Close;
335 336
337 error = dpm_prepare(PMSG_FREEZE);
338 if (error)
339 goto Complete_devices;
340
336 /* Preallocate image memory before shutting down devices. */ 341 /* Preallocate image memory before shutting down devices. */
337 error = hibernate_preallocate_memory(); 342 error = hibernate_preallocate_memory();
338 if (error) 343 if (error)
339 goto Close; 344 goto Complete_devices;
340 345
341 suspend_console(); 346 suspend_console();
342 pm_restrict_gfp_mask(); 347 pm_restrict_gfp_mask();
343 error = dpm_suspend_start(PMSG_FREEZE); 348 error = dpm_suspend(PMSG_FREEZE);
344 if (error) 349 if (error)
345 goto Recover_platform; 350 goto Recover_platform;
346 351
@@ -358,13 +363,17 @@ int hibernation_snapshot(int platform_mode)
358 if (error || !in_suspend) 363 if (error || !in_suspend)
359 swsusp_free(); 364 swsusp_free();
360 365
361 dpm_resume_end(in_suspend ? 366 msg = in_suspend ? (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE;
362 (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE); 367 dpm_resume(msg);
363 368
364 if (error || !in_suspend) 369 if (error || !in_suspend)
365 pm_restore_gfp_mask(); 370 pm_restore_gfp_mask();
366 371
367 resume_console(); 372 resume_console();
373
374 Complete_devices:
375 dpm_complete(msg);
376
368 Close: 377 Close:
369 platform_end(platform_mode); 378 platform_end(platform_mode);
370 return error; 379 return error;