diff options
author | Grant Likely <grant.likely@secretlab.ca> | 2010-12-30 00:20:30 -0500 |
---|---|---|
committer | Grant Likely <grant.likely@secretlab.ca> | 2010-12-30 00:21:47 -0500 |
commit | d392da5207352f09030e95d9ea335a4225667ec0 (patch) | |
tree | 7d6cd1932afcad0a5619a5c504a6d93ca318187c /kernel/power | |
parent | e39d5ef678045d61812c1401f04fe8edb14d6359 (diff) | |
parent | 387c31c7e5c9805b0aef8833d1731a5fe7bdea14 (diff) |
Merge v2.6.37-rc8 into powerpc/next
Diffstat (limited to 'kernel/power')
-rw-r--r-- | kernel/power/Kconfig | 21 | ||||
-rw-r--r-- | kernel/power/block_io.c | 2 | ||||
-rw-r--r-- | kernel/power/hibernate.c | 48 | ||||
-rw-r--r-- | kernel/power/main.c | 29 | ||||
-rw-r--r-- | kernel/power/power.h | 10 | ||||
-rw-r--r-- | kernel/power/poweroff.c | 2 | ||||
-rw-r--r-- | kernel/power/process.c | 11 | ||||
-rw-r--r-- | kernel/power/snapshot.c | 117 | ||||
-rw-r--r-- | kernel/power/suspend.c | 5 | ||||
-rw-r--r-- | kernel/power/swap.c | 335 | ||||
-rw-r--r-- | kernel/power/user.c | 4 |
11 files changed, 502 insertions, 82 deletions
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig index ca6066a6952e..a5aff3ebad38 100644 --- a/kernel/power/Kconfig +++ b/kernel/power/Kconfig | |||
@@ -86,6 +86,7 @@ config PM_SLEEP_SMP | |||
86 | depends on SMP | 86 | depends on SMP |
87 | depends on ARCH_SUSPEND_POSSIBLE || ARCH_HIBERNATION_POSSIBLE | 87 | depends on ARCH_SUSPEND_POSSIBLE || ARCH_HIBERNATION_POSSIBLE |
88 | depends on PM_SLEEP | 88 | depends on PM_SLEEP |
89 | select HOTPLUG | ||
89 | select HOTPLUG_CPU | 90 | select HOTPLUG_CPU |
90 | default y | 91 | default y |
91 | 92 | ||
@@ -137,6 +138,8 @@ config SUSPEND_FREEZER | |||
137 | config HIBERNATION | 138 | config HIBERNATION |
138 | bool "Hibernation (aka 'suspend to disk')" | 139 | bool "Hibernation (aka 'suspend to disk')" |
139 | depends on PM && SWAP && ARCH_HIBERNATION_POSSIBLE | 140 | depends on PM && SWAP && ARCH_HIBERNATION_POSSIBLE |
141 | select LZO_COMPRESS | ||
142 | select LZO_DECOMPRESS | ||
140 | select SUSPEND_NVS if HAS_IOMEM | 143 | select SUSPEND_NVS if HAS_IOMEM |
141 | ---help--- | 144 | ---help--- |
142 | Enable the suspend to disk (STD) functionality, which is usually | 145 | Enable the suspend to disk (STD) functionality, which is usually |
@@ -242,3 +245,21 @@ config PM_OPS | |||
242 | bool | 245 | bool |
243 | depends on PM_SLEEP || PM_RUNTIME | 246 | depends on PM_SLEEP || PM_RUNTIME |
244 | default y | 247 | default y |
248 | |||
249 | config ARCH_HAS_OPP | ||
250 | bool | ||
251 | |||
252 | config PM_OPP | ||
253 | bool "Operating Performance Point (OPP) Layer library" | ||
254 | depends on PM | ||
255 | depends on ARCH_HAS_OPP | ||
256 | ---help--- | ||
257 | SOCs have a standard set of tuples consisting of frequency and | ||
258 | voltage pairs that the device will support per voltage domain. This | ||
259 | is called Operating Performance Point or OPP. The actual definitions | ||
260 | of OPP varies over silicon within the same family of devices. | ||
261 | |||
262 | OPP layer organizes the data internally using device pointers | ||
263 | representing individual voltage domains and provides SOC | ||
264 | implementations a ready to use framework to manage OPPs. | ||
265 | For more information, read <file:Documentation/power/opp.txt> | ||
diff --git a/kernel/power/block_io.c b/kernel/power/block_io.c index 97024fd40cd5..83bbc7c02df9 100644 --- a/kernel/power/block_io.c +++ b/kernel/power/block_io.c | |||
@@ -28,7 +28,7 @@ | |||
28 | static int submit(int rw, struct block_device *bdev, sector_t sector, | 28 | static int submit(int rw, struct block_device *bdev, sector_t sector, |
29 | struct page *page, struct bio **bio_chain) | 29 | struct page *page, struct bio **bio_chain) |
30 | { | 30 | { |
31 | const int bio_rw = rw | (1 << BIO_RW_SYNCIO) | (1 << BIO_RW_UNPLUG); | 31 | const int bio_rw = rw | REQ_SYNC | REQ_UNPLUG; |
32 | struct bio *bio; | 32 | struct bio *bio; |
33 | 33 | ||
34 | bio = bio_alloc(__GFP_WAIT | __GFP_HIGH, 1); | 34 | bio = bio_alloc(__GFP_WAIT | __GFP_HIGH, 1); |
diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c index c77963938bca..048d0b514831 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include "power.h" | 29 | #include "power.h" |
30 | 30 | ||
31 | 31 | ||
32 | static int nocompress = 0; | ||
32 | static int noresume = 0; | 33 | static int noresume = 0; |
33 | static char resume_file[256] = CONFIG_PM_STD_PARTITION; | 34 | static char resume_file[256] = CONFIG_PM_STD_PARTITION; |
34 | dev_t swsusp_resume_device; | 35 | dev_t swsusp_resume_device; |
@@ -326,7 +327,6 @@ static int create_image(int platform_mode) | |||
326 | int hibernation_snapshot(int platform_mode) | 327 | int hibernation_snapshot(int platform_mode) |
327 | { | 328 | { |
328 | int error; | 329 | int error; |
329 | gfp_t saved_mask; | ||
330 | 330 | ||
331 | error = platform_begin(platform_mode); | 331 | error = platform_begin(platform_mode); |
332 | if (error) | 332 | if (error) |
@@ -338,8 +338,7 @@ int hibernation_snapshot(int platform_mode) | |||
338 | goto Close; | 338 | goto Close; |
339 | 339 | ||
340 | suspend_console(); | 340 | suspend_console(); |
341 | hibernation_freeze_swap(); | 341 | pm_restrict_gfp_mask(); |
342 | saved_mask = clear_gfp_allowed_mask(GFP_IOFS); | ||
343 | error = dpm_suspend_start(PMSG_FREEZE); | 342 | error = dpm_suspend_start(PMSG_FREEZE); |
344 | if (error) | 343 | if (error) |
345 | goto Recover_platform; | 344 | goto Recover_platform; |
@@ -348,7 +347,10 @@ int hibernation_snapshot(int platform_mode) | |||
348 | goto Recover_platform; | 347 | goto Recover_platform; |
349 | 348 | ||
350 | error = create_image(platform_mode); | 349 | error = create_image(platform_mode); |
351 | /* Control returns here after successful restore */ | 350 | /* |
351 | * Control returns here (1) after the image has been created or the | ||
352 | * image creation has failed and (2) after a successful restore. | ||
353 | */ | ||
352 | 354 | ||
353 | Resume_devices: | 355 | Resume_devices: |
354 | /* We may need to release the preallocated image pages here. */ | 356 | /* We may need to release the preallocated image pages here. */ |
@@ -357,7 +359,10 @@ int hibernation_snapshot(int platform_mode) | |||
357 | 359 | ||
358 | dpm_resume_end(in_suspend ? | 360 | dpm_resume_end(in_suspend ? |
359 | (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE); | 361 | (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE); |
360 | set_gfp_allowed_mask(saved_mask); | 362 | |
363 | if (error || !in_suspend) | ||
364 | pm_restore_gfp_mask(); | ||
365 | |||
361 | resume_console(); | 366 | resume_console(); |
362 | Close: | 367 | Close: |
363 | platform_end(platform_mode); | 368 | platform_end(platform_mode); |
@@ -452,17 +457,16 @@ static int resume_target_kernel(bool platform_mode) | |||
452 | int hibernation_restore(int platform_mode) | 457 | int hibernation_restore(int platform_mode) |
453 | { | 458 | { |
454 | int error; | 459 | int error; |
455 | gfp_t saved_mask; | ||
456 | 460 | ||
457 | pm_prepare_console(); | 461 | pm_prepare_console(); |
458 | suspend_console(); | 462 | suspend_console(); |
459 | saved_mask = clear_gfp_allowed_mask(GFP_IOFS); | 463 | pm_restrict_gfp_mask(); |
460 | error = dpm_suspend_start(PMSG_QUIESCE); | 464 | error = dpm_suspend_start(PMSG_QUIESCE); |
461 | if (!error) { | 465 | if (!error) { |
462 | error = resume_target_kernel(platform_mode); | 466 | error = resume_target_kernel(platform_mode); |
463 | dpm_resume_end(PMSG_RECOVER); | 467 | dpm_resume_end(PMSG_RECOVER); |
464 | } | 468 | } |
465 | set_gfp_allowed_mask(saved_mask); | 469 | pm_restore_gfp_mask(); |
466 | resume_console(); | 470 | resume_console(); |
467 | pm_restore_console(); | 471 | pm_restore_console(); |
468 | return error; | 472 | return error; |
@@ -476,7 +480,6 @@ int hibernation_restore(int platform_mode) | |||
476 | int hibernation_platform_enter(void) | 480 | int hibernation_platform_enter(void) |
477 | { | 481 | { |
478 | int error; | 482 | int error; |
479 | gfp_t saved_mask; | ||
480 | 483 | ||
481 | if (!hibernation_ops) | 484 | if (!hibernation_ops) |
482 | return -ENOSYS; | 485 | return -ENOSYS; |
@@ -492,7 +495,6 @@ int hibernation_platform_enter(void) | |||
492 | 495 | ||
493 | entering_platform_hibernation = true; | 496 | entering_platform_hibernation = true; |
494 | suspend_console(); | 497 | suspend_console(); |
495 | saved_mask = clear_gfp_allowed_mask(GFP_IOFS); | ||
496 | error = dpm_suspend_start(PMSG_HIBERNATE); | 498 | error = dpm_suspend_start(PMSG_HIBERNATE); |
497 | if (error) { | 499 | if (error) { |
498 | if (hibernation_ops->recover) | 500 | if (hibernation_ops->recover) |
@@ -536,7 +538,6 @@ int hibernation_platform_enter(void) | |||
536 | Resume_devices: | 538 | Resume_devices: |
537 | entering_platform_hibernation = false; | 539 | entering_platform_hibernation = false; |
538 | dpm_resume_end(PMSG_RESTORE); | 540 | dpm_resume_end(PMSG_RESTORE); |
539 | set_gfp_allowed_mask(saved_mask); | ||
540 | resume_console(); | 541 | resume_console(); |
541 | 542 | ||
542 | Close: | 543 | Close: |
@@ -639,11 +640,14 @@ int hibernate(void) | |||
639 | 640 | ||
640 | if (hibernation_mode == HIBERNATION_PLATFORM) | 641 | if (hibernation_mode == HIBERNATION_PLATFORM) |
641 | flags |= SF_PLATFORM_MODE; | 642 | flags |= SF_PLATFORM_MODE; |
643 | if (nocompress) | ||
644 | flags |= SF_NOCOMPRESS_MODE; | ||
642 | pr_debug("PM: writing image.\n"); | 645 | pr_debug("PM: writing image.\n"); |
643 | error = swsusp_write(flags); | 646 | error = swsusp_write(flags); |
644 | swsusp_free(); | 647 | swsusp_free(); |
645 | if (!error) | 648 | if (!error) |
646 | power_down(); | 649 | power_down(); |
650 | pm_restore_gfp_mask(); | ||
647 | } else { | 651 | } else { |
648 | pr_debug("PM: Image restored successfully.\n"); | 652 | pr_debug("PM: Image restored successfully.\n"); |
649 | } | 653 | } |
@@ -706,7 +710,7 @@ static int software_resume(void) | |||
706 | goto Unlock; | 710 | goto Unlock; |
707 | } | 711 | } |
708 | 712 | ||
709 | pr_debug("PM: Checking image partition %s\n", resume_file); | 713 | pr_debug("PM: Checking hibernation image partition %s\n", resume_file); |
710 | 714 | ||
711 | /* Check if the device is there */ | 715 | /* Check if the device is there */ |
712 | swsusp_resume_device = name_to_dev_t(resume_file); | 716 | swsusp_resume_device = name_to_dev_t(resume_file); |
@@ -731,10 +735,10 @@ static int software_resume(void) | |||
731 | } | 735 | } |
732 | 736 | ||
733 | Check_image: | 737 | Check_image: |
734 | pr_debug("PM: Resume from partition %d:%d\n", | 738 | pr_debug("PM: Hibernation image partition %d:%d present\n", |
735 | MAJOR(swsusp_resume_device), MINOR(swsusp_resume_device)); | 739 | MAJOR(swsusp_resume_device), MINOR(swsusp_resume_device)); |
736 | 740 | ||
737 | pr_debug("PM: Checking hibernation image.\n"); | 741 | pr_debug("PM: Looking for hibernation image.\n"); |
738 | error = swsusp_check(); | 742 | error = swsusp_check(); |
739 | if (error) | 743 | if (error) |
740 | goto Unlock; | 744 | goto Unlock; |
@@ -766,14 +770,14 @@ static int software_resume(void) | |||
766 | goto Done; | 770 | goto Done; |
767 | } | 771 | } |
768 | 772 | ||
769 | pr_debug("PM: Reading hibernation image.\n"); | 773 | pr_debug("PM: Loading hibernation image.\n"); |
770 | 774 | ||
771 | error = swsusp_read(&flags); | 775 | error = swsusp_read(&flags); |
772 | swsusp_close(FMODE_READ); | 776 | swsusp_close(FMODE_READ); |
773 | if (!error) | 777 | if (!error) |
774 | hibernation_restore(flags & SF_PLATFORM_MODE); | 778 | hibernation_restore(flags & SF_PLATFORM_MODE); |
775 | 779 | ||
776 | printk(KERN_ERR "PM: Restore failed, recovering.\n"); | 780 | printk(KERN_ERR "PM: Failed to load hibernation image, recovering.\n"); |
777 | swsusp_free(); | 781 | swsusp_free(); |
778 | thaw_processes(); | 782 | thaw_processes(); |
779 | Done: | 783 | Done: |
@@ -786,7 +790,7 @@ static int software_resume(void) | |||
786 | /* For success case, the suspend path will release the lock */ | 790 | /* For success case, the suspend path will release the lock */ |
787 | Unlock: | 791 | Unlock: |
788 | mutex_unlock(&pm_mutex); | 792 | mutex_unlock(&pm_mutex); |
789 | pr_debug("PM: Resume from disk failed.\n"); | 793 | pr_debug("PM: Hibernation image not present or could not be loaded.\n"); |
790 | return error; | 794 | return error; |
791 | close_finish: | 795 | close_finish: |
792 | swsusp_close(FMODE_READ); | 796 | swsusp_close(FMODE_READ); |
@@ -1005,6 +1009,15 @@ static int __init resume_offset_setup(char *str) | |||
1005 | return 1; | 1009 | return 1; |
1006 | } | 1010 | } |
1007 | 1011 | ||
1012 | static int __init hibernate_setup(char *str) | ||
1013 | { | ||
1014 | if (!strncmp(str, "noresume", 8)) | ||
1015 | noresume = 1; | ||
1016 | else if (!strncmp(str, "nocompress", 10)) | ||
1017 | nocompress = 1; | ||
1018 | return 1; | ||
1019 | } | ||
1020 | |||
1008 | static int __init noresume_setup(char *str) | 1021 | static int __init noresume_setup(char *str) |
1009 | { | 1022 | { |
1010 | noresume = 1; | 1023 | noresume = 1; |
@@ -1014,3 +1027,4 @@ static int __init noresume_setup(char *str) | |||
1014 | __setup("noresume", noresume_setup); | 1027 | __setup("noresume", noresume_setup); |
1015 | __setup("resume_offset=", resume_offset_setup); | 1028 | __setup("resume_offset=", resume_offset_setup); |
1016 | __setup("resume=", resume_setup); | 1029 | __setup("resume=", resume_setup); |
1030 | __setup("hibernate=", hibernate_setup); | ||
diff --git a/kernel/power/main.c b/kernel/power/main.c index 62b0bc6e4983..7b5db6a8561e 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c | |||
@@ -237,18 +237,18 @@ static ssize_t wakeup_count_show(struct kobject *kobj, | |||
237 | struct kobj_attribute *attr, | 237 | struct kobj_attribute *attr, |
238 | char *buf) | 238 | char *buf) |
239 | { | 239 | { |
240 | unsigned long val; | 240 | unsigned int val; |
241 | 241 | ||
242 | return pm_get_wakeup_count(&val) ? sprintf(buf, "%lu\n", val) : -EINTR; | 242 | return pm_get_wakeup_count(&val) ? sprintf(buf, "%u\n", val) : -EINTR; |
243 | } | 243 | } |
244 | 244 | ||
245 | static ssize_t wakeup_count_store(struct kobject *kobj, | 245 | static ssize_t wakeup_count_store(struct kobject *kobj, |
246 | struct kobj_attribute *attr, | 246 | struct kobj_attribute *attr, |
247 | const char *buf, size_t n) | 247 | const char *buf, size_t n) |
248 | { | 248 | { |
249 | unsigned long val; | 249 | unsigned int val; |
250 | 250 | ||
251 | if (sscanf(buf, "%lu", &val) == 1) { | 251 | if (sscanf(buf, "%u", &val) == 1) { |
252 | if (pm_save_wakeup_count(val)) | 252 | if (pm_save_wakeup_count(val)) |
253 | return n; | 253 | return n; |
254 | } | 254 | } |
@@ -281,12 +281,30 @@ pm_trace_store(struct kobject *kobj, struct kobj_attribute *attr, | |||
281 | } | 281 | } |
282 | 282 | ||
283 | power_attr(pm_trace); | 283 | power_attr(pm_trace); |
284 | |||
285 | static ssize_t pm_trace_dev_match_show(struct kobject *kobj, | ||
286 | struct kobj_attribute *attr, | ||
287 | char *buf) | ||
288 | { | ||
289 | return show_trace_dev_match(buf, PAGE_SIZE); | ||
290 | } | ||
291 | |||
292 | static ssize_t | ||
293 | pm_trace_dev_match_store(struct kobject *kobj, struct kobj_attribute *attr, | ||
294 | const char *buf, size_t n) | ||
295 | { | ||
296 | return -EINVAL; | ||
297 | } | ||
298 | |||
299 | power_attr(pm_trace_dev_match); | ||
300 | |||
284 | #endif /* CONFIG_PM_TRACE */ | 301 | #endif /* CONFIG_PM_TRACE */ |
285 | 302 | ||
286 | static struct attribute * g[] = { | 303 | static struct attribute * g[] = { |
287 | &state_attr.attr, | 304 | &state_attr.attr, |
288 | #ifdef CONFIG_PM_TRACE | 305 | #ifdef CONFIG_PM_TRACE |
289 | &pm_trace_attr.attr, | 306 | &pm_trace_attr.attr, |
307 | &pm_trace_dev_match_attr.attr, | ||
290 | #endif | 308 | #endif |
291 | #ifdef CONFIG_PM_SLEEP | 309 | #ifdef CONFIG_PM_SLEEP |
292 | &pm_async_attr.attr, | 310 | &pm_async_attr.attr, |
@@ -308,7 +326,7 @@ EXPORT_SYMBOL_GPL(pm_wq); | |||
308 | 326 | ||
309 | static int __init pm_start_workqueue(void) | 327 | static int __init pm_start_workqueue(void) |
310 | { | 328 | { |
311 | pm_wq = create_freezeable_workqueue("pm"); | 329 | pm_wq = alloc_workqueue("pm", WQ_FREEZEABLE, 0); |
312 | 330 | ||
313 | return pm_wq ? 0 : -ENOMEM; | 331 | return pm_wq ? 0 : -ENOMEM; |
314 | } | 332 | } |
@@ -321,6 +339,7 @@ static int __init pm_init(void) | |||
321 | int error = pm_start_workqueue(); | 339 | int error = pm_start_workqueue(); |
322 | if (error) | 340 | if (error) |
323 | return error; | 341 | return error; |
342 | hibernate_image_size_init(); | ||
324 | power_kobj = kobject_create_and_add("power", NULL); | 343 | power_kobj = kobject_create_and_add("power", NULL); |
325 | if (!power_kobj) | 344 | if (!power_kobj) |
326 | return -ENOMEM; | 345 | return -ENOMEM; |
diff --git a/kernel/power/power.h b/kernel/power/power.h index 006270fe382d..03634be55f62 100644 --- a/kernel/power/power.h +++ b/kernel/power/power.h | |||
@@ -14,6 +14,9 @@ struct swsusp_info { | |||
14 | } __attribute__((aligned(PAGE_SIZE))); | 14 | } __attribute__((aligned(PAGE_SIZE))); |
15 | 15 | ||
16 | #ifdef CONFIG_HIBERNATION | 16 | #ifdef CONFIG_HIBERNATION |
17 | /* kernel/power/snapshot.c */ | ||
18 | extern void __init hibernate_image_size_init(void); | ||
19 | |||
17 | #ifdef CONFIG_ARCH_HIBERNATION_HEADER | 20 | #ifdef CONFIG_ARCH_HIBERNATION_HEADER |
18 | /* Maximum size of architecture specific data in a hibernation header */ | 21 | /* Maximum size of architecture specific data in a hibernation header */ |
19 | #define MAX_ARCH_HEADER_SIZE (sizeof(struct new_utsname) + 4) | 22 | #define MAX_ARCH_HEADER_SIZE (sizeof(struct new_utsname) + 4) |
@@ -49,7 +52,11 @@ static inline char *check_image_kernel(struct swsusp_info *info) | |||
49 | extern int hibernation_snapshot(int platform_mode); | 52 | extern int hibernation_snapshot(int platform_mode); |
50 | extern int hibernation_restore(int platform_mode); | 53 | extern int hibernation_restore(int platform_mode); |
51 | extern int hibernation_platform_enter(void); | 54 | extern int hibernation_platform_enter(void); |
52 | #endif | 55 | |
56 | #else /* !CONFIG_HIBERNATION */ | ||
57 | |||
58 | static inline void hibernate_image_size_init(void) {} | ||
59 | #endif /* !CONFIG_HIBERNATION */ | ||
53 | 60 | ||
54 | extern int pfn_is_nosave(unsigned long); | 61 | extern int pfn_is_nosave(unsigned long); |
55 | 62 | ||
@@ -134,6 +141,7 @@ extern int swsusp_swap_in_use(void); | |||
134 | * the image header. | 141 | * the image header. |
135 | */ | 142 | */ |
136 | #define SF_PLATFORM_MODE 1 | 143 | #define SF_PLATFORM_MODE 1 |
144 | #define SF_NOCOMPRESS_MODE 2 | ||
137 | 145 | ||
138 | /* kernel/power/hibernate.c */ | 146 | /* kernel/power/hibernate.c */ |
139 | extern int swsusp_check(void); | 147 | extern int swsusp_check(void); |
diff --git a/kernel/power/poweroff.c b/kernel/power/poweroff.c index e8b337006276..d52359374e85 100644 --- a/kernel/power/poweroff.c +++ b/kernel/power/poweroff.c | |||
@@ -24,7 +24,7 @@ static void do_poweroff(struct work_struct *dummy) | |||
24 | 24 | ||
25 | static DECLARE_WORK(poweroff_work, do_poweroff); | 25 | static DECLARE_WORK(poweroff_work, do_poweroff); |
26 | 26 | ||
27 | static void handle_poweroff(int key, struct tty_struct *tty) | 27 | static void handle_poweroff(int key) |
28 | { | 28 | { |
29 | /* run sysrq poweroff on boot cpu */ | 29 | /* run sysrq poweroff on boot cpu */ |
30 | schedule_work_on(cpumask_first(cpu_online_mask), &poweroff_work); | 30 | schedule_work_on(cpumask_first(cpu_online_mask), &poweroff_work); |
diff --git a/kernel/power/process.c b/kernel/power/process.c index 028a99598f49..e50b4c1b2a0f 100644 --- a/kernel/power/process.c +++ b/kernel/power/process.c | |||
@@ -40,6 +40,7 @@ static int try_to_freeze_tasks(bool sig_only) | |||
40 | struct timeval start, end; | 40 | struct timeval start, end; |
41 | u64 elapsed_csecs64; | 41 | u64 elapsed_csecs64; |
42 | unsigned int elapsed_csecs; | 42 | unsigned int elapsed_csecs; |
43 | bool wakeup = false; | ||
43 | 44 | ||
44 | do_gettimeofday(&start); | 45 | do_gettimeofday(&start); |
45 | 46 | ||
@@ -78,6 +79,11 @@ static int try_to_freeze_tasks(bool sig_only) | |||
78 | if (!todo || time_after(jiffies, end_time)) | 79 | if (!todo || time_after(jiffies, end_time)) |
79 | break; | 80 | break; |
80 | 81 | ||
82 | if (!pm_check_wakeup_events()) { | ||
83 | wakeup = true; | ||
84 | break; | ||
85 | } | ||
86 | |||
81 | /* | 87 | /* |
82 | * We need to retry, but first give the freezing tasks some | 88 | * We need to retry, but first give the freezing tasks some |
83 | * time to enter the regrigerator. | 89 | * time to enter the regrigerator. |
@@ -97,8 +103,9 @@ static int try_to_freeze_tasks(bool sig_only) | |||
97 | * but it cleans up leftover PF_FREEZE requests. | 103 | * but it cleans up leftover PF_FREEZE requests. |
98 | */ | 104 | */ |
99 | printk("\n"); | 105 | printk("\n"); |
100 | printk(KERN_ERR "Freezing of tasks failed after %d.%02d seconds " | 106 | printk(KERN_ERR "Freezing of tasks %s after %d.%02d seconds " |
101 | "(%d tasks refusing to freeze, wq_busy=%d):\n", | 107 | "(%d tasks refusing to freeze, wq_busy=%d):\n", |
108 | wakeup ? "aborted" : "failed", | ||
102 | elapsed_csecs / 100, elapsed_csecs % 100, | 109 | elapsed_csecs / 100, elapsed_csecs % 100, |
103 | todo - wq_busy, wq_busy); | 110 | todo - wq_busy, wq_busy); |
104 | 111 | ||
@@ -107,7 +114,7 @@ static int try_to_freeze_tasks(bool sig_only) | |||
107 | read_lock(&tasklist_lock); | 114 | read_lock(&tasklist_lock); |
108 | do_each_thread(g, p) { | 115 | do_each_thread(g, p) { |
109 | task_lock(p); | 116 | task_lock(p); |
110 | if (freezing(p) && !freezer_should_skip(p)) | 117 | if (!wakeup && freezing(p) && !freezer_should_skip(p)) |
111 | sched_show_task(p); | 118 | sched_show_task(p); |
112 | cancel_freezing(p); | 119 | cancel_freezing(p); |
113 | task_unlock(p); | 120 | task_unlock(p); |
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c index 5e7edfb05e66..0dac75ea4456 100644 --- a/kernel/power/snapshot.c +++ b/kernel/power/snapshot.c | |||
@@ -46,7 +46,12 @@ static void swsusp_unset_page_forbidden(struct page *); | |||
46 | * size will not exceed N bytes, but if that is impossible, it will | 46 | * size will not exceed N bytes, but if that is impossible, it will |
47 | * try to create the smallest image possible. | 47 | * try to create the smallest image possible. |
48 | */ | 48 | */ |
49 | unsigned long image_size = 500 * 1024 * 1024; | 49 | unsigned long image_size; |
50 | |||
51 | void __init hibernate_image_size_init(void) | ||
52 | { | ||
53 | image_size = ((totalram_pages * 2) / 5) * PAGE_SIZE; | ||
54 | } | ||
50 | 55 | ||
51 | /* List of PBEs needed for restoring the pages that were allocated before | 56 | /* List of PBEs needed for restoring the pages that were allocated before |
52 | * the suspend and included in the suspend image, but have also been | 57 | * the suspend and included in the suspend image, but have also been |
@@ -979,8 +984,8 @@ static void copy_data_page(unsigned long dst_pfn, unsigned long src_pfn) | |||
979 | src = kmap_atomic(s_page, KM_USER0); | 984 | src = kmap_atomic(s_page, KM_USER0); |
980 | dst = kmap_atomic(d_page, KM_USER1); | 985 | dst = kmap_atomic(d_page, KM_USER1); |
981 | do_copy_page(dst, src); | 986 | do_copy_page(dst, src); |
982 | kunmap_atomic(src, KM_USER0); | ||
983 | kunmap_atomic(dst, KM_USER1); | 987 | kunmap_atomic(dst, KM_USER1); |
988 | kunmap_atomic(src, KM_USER0); | ||
984 | } else { | 989 | } else { |
985 | if (PageHighMem(d_page)) { | 990 | if (PageHighMem(d_page)) { |
986 | /* Page pointed to by src may contain some kernel | 991 | /* Page pointed to by src may contain some kernel |
@@ -988,7 +993,7 @@ static void copy_data_page(unsigned long dst_pfn, unsigned long src_pfn) | |||
988 | */ | 993 | */ |
989 | safe_copy_page(buffer, s_page); | 994 | safe_copy_page(buffer, s_page); |
990 | dst = kmap_atomic(d_page, KM_USER0); | 995 | dst = kmap_atomic(d_page, KM_USER0); |
991 | memcpy(dst, buffer, PAGE_SIZE); | 996 | copy_page(dst, buffer); |
992 | kunmap_atomic(dst, KM_USER0); | 997 | kunmap_atomic(dst, KM_USER0); |
993 | } else { | 998 | } else { |
994 | safe_copy_page(page_address(d_page), s_page); | 999 | safe_copy_page(page_address(d_page), s_page); |
@@ -1086,7 +1091,6 @@ void swsusp_free(void) | |||
1086 | buffer = NULL; | 1091 | buffer = NULL; |
1087 | alloc_normal = 0; | 1092 | alloc_normal = 0; |
1088 | alloc_highmem = 0; | 1093 | alloc_highmem = 0; |
1089 | hibernation_thaw_swap(); | ||
1090 | } | 1094 | } |
1091 | 1095 | ||
1092 | /* Helper functions used for the shrinking of memory. */ | 1096 | /* Helper functions used for the shrinking of memory. */ |
@@ -1122,9 +1126,19 @@ static unsigned long preallocate_image_pages(unsigned long nr_pages, gfp_t mask) | |||
1122 | return nr_alloc; | 1126 | return nr_alloc; |
1123 | } | 1127 | } |
1124 | 1128 | ||
1125 | static unsigned long preallocate_image_memory(unsigned long nr_pages) | 1129 | static unsigned long preallocate_image_memory(unsigned long nr_pages, |
1130 | unsigned long avail_normal) | ||
1126 | { | 1131 | { |
1127 | return preallocate_image_pages(nr_pages, GFP_IMAGE); | 1132 | unsigned long alloc; |
1133 | |||
1134 | if (avail_normal <= alloc_normal) | ||
1135 | return 0; | ||
1136 | |||
1137 | alloc = avail_normal - alloc_normal; | ||
1138 | if (nr_pages < alloc) | ||
1139 | alloc = nr_pages; | ||
1140 | |||
1141 | return preallocate_image_pages(alloc, GFP_IMAGE); | ||
1128 | } | 1142 | } |
1129 | 1143 | ||
1130 | #ifdef CONFIG_HIGHMEM | 1144 | #ifdef CONFIG_HIGHMEM |
@@ -1170,15 +1184,22 @@ static inline unsigned long preallocate_highmem_fraction(unsigned long nr_pages, | |||
1170 | */ | 1184 | */ |
1171 | static void free_unnecessary_pages(void) | 1185 | static void free_unnecessary_pages(void) |
1172 | { | 1186 | { |
1173 | unsigned long save_highmem, to_free_normal, to_free_highmem; | 1187 | unsigned long save, to_free_normal, to_free_highmem; |
1174 | 1188 | ||
1175 | to_free_normal = alloc_normal - count_data_pages(); | 1189 | save = count_data_pages(); |
1176 | save_highmem = count_highmem_pages(); | 1190 | if (alloc_normal >= save) { |
1177 | if (alloc_highmem > save_highmem) { | 1191 | to_free_normal = alloc_normal - save; |
1178 | to_free_highmem = alloc_highmem - save_highmem; | 1192 | save = 0; |
1193 | } else { | ||
1194 | to_free_normal = 0; | ||
1195 | save -= alloc_normal; | ||
1196 | } | ||
1197 | save += count_highmem_pages(); | ||
1198 | if (alloc_highmem >= save) { | ||
1199 | to_free_highmem = alloc_highmem - save; | ||
1179 | } else { | 1200 | } else { |
1180 | to_free_highmem = 0; | 1201 | to_free_highmem = 0; |
1181 | to_free_normal -= save_highmem - alloc_highmem; | 1202 | to_free_normal -= save - alloc_highmem; |
1182 | } | 1203 | } |
1183 | 1204 | ||
1184 | memory_bm_position_reset(©_bm); | 1205 | memory_bm_position_reset(©_bm); |
@@ -1259,7 +1280,7 @@ int hibernate_preallocate_memory(void) | |||
1259 | { | 1280 | { |
1260 | struct zone *zone; | 1281 | struct zone *zone; |
1261 | unsigned long saveable, size, max_size, count, highmem, pages = 0; | 1282 | unsigned long saveable, size, max_size, count, highmem, pages = 0; |
1262 | unsigned long alloc, save_highmem, pages_highmem; | 1283 | unsigned long alloc, save_highmem, pages_highmem, avail_normal; |
1263 | struct timeval start, stop; | 1284 | struct timeval start, stop; |
1264 | int error; | 1285 | int error; |
1265 | 1286 | ||
@@ -1296,26 +1317,38 @@ int hibernate_preallocate_memory(void) | |||
1296 | else | 1317 | else |
1297 | count += zone_page_state(zone, NR_FREE_PAGES); | 1318 | count += zone_page_state(zone, NR_FREE_PAGES); |
1298 | } | 1319 | } |
1320 | avail_normal = count; | ||
1299 | count += highmem; | 1321 | count += highmem; |
1300 | count -= totalreserve_pages; | 1322 | count -= totalreserve_pages; |
1301 | 1323 | ||
1302 | /* Compute the maximum number of saveable pages to leave in memory. */ | 1324 | /* Compute the maximum number of saveable pages to leave in memory. */ |
1303 | max_size = (count - (size + PAGES_FOR_IO)) / 2 - 2 * SPARE_PAGES; | 1325 | max_size = (count - (size + PAGES_FOR_IO)) / 2 - 2 * SPARE_PAGES; |
1326 | /* Compute the desired number of image pages specified by image_size. */ | ||
1304 | size = DIV_ROUND_UP(image_size, PAGE_SIZE); | 1327 | size = DIV_ROUND_UP(image_size, PAGE_SIZE); |
1305 | if (size > max_size) | 1328 | if (size > max_size) |
1306 | size = max_size; | 1329 | size = max_size; |
1307 | /* | 1330 | /* |
1308 | * If the maximum is not less than the current number of saveable pages | 1331 | * If the desired number of image pages is at least as large as the |
1309 | * in memory, allocate page frames for the image and we're done. | 1332 | * current number of saveable pages in memory, allocate page frames for |
1333 | * the image and we're done. | ||
1310 | */ | 1334 | */ |
1311 | if (size >= saveable) { | 1335 | if (size >= saveable) { |
1312 | pages = preallocate_image_highmem(save_highmem); | 1336 | pages = preallocate_image_highmem(save_highmem); |
1313 | pages += preallocate_image_memory(saveable - pages); | 1337 | pages += preallocate_image_memory(saveable - pages, avail_normal); |
1314 | goto out; | 1338 | goto out; |
1315 | } | 1339 | } |
1316 | 1340 | ||
1317 | /* Estimate the minimum size of the image. */ | 1341 | /* Estimate the minimum size of the image. */ |
1318 | pages = minimum_image_size(saveable); | 1342 | pages = minimum_image_size(saveable); |
1343 | /* | ||
1344 | * To avoid excessive pressure on the normal zone, leave room in it to | ||
1345 | * accommodate an image of the minimum size (unless it's already too | ||
1346 | * small, in which case don't preallocate pages from it at all). | ||
1347 | */ | ||
1348 | if (avail_normal > pages) | ||
1349 | avail_normal -= pages; | ||
1350 | else | ||
1351 | avail_normal = 0; | ||
1319 | if (size < pages) | 1352 | if (size < pages) |
1320 | size = min_t(unsigned long, pages, max_size); | 1353 | size = min_t(unsigned long, pages, max_size); |
1321 | 1354 | ||
@@ -1336,16 +1369,34 @@ int hibernate_preallocate_memory(void) | |||
1336 | */ | 1369 | */ |
1337 | pages_highmem = preallocate_image_highmem(highmem / 2); | 1370 | pages_highmem = preallocate_image_highmem(highmem / 2); |
1338 | alloc = (count - max_size) - pages_highmem; | 1371 | alloc = (count - max_size) - pages_highmem; |
1339 | pages = preallocate_image_memory(alloc); | 1372 | pages = preallocate_image_memory(alloc, avail_normal); |
1340 | if (pages < alloc) | 1373 | if (pages < alloc) { |
1341 | goto err_out; | 1374 | /* We have exhausted non-highmem pages, try highmem. */ |
1342 | size = max_size - size; | 1375 | alloc -= pages; |
1343 | alloc = size; | 1376 | pages += pages_highmem; |
1344 | size = preallocate_highmem_fraction(size, highmem, count); | 1377 | pages_highmem = preallocate_image_highmem(alloc); |
1345 | pages_highmem += size; | 1378 | if (pages_highmem < alloc) |
1346 | alloc -= size; | 1379 | goto err_out; |
1347 | pages += preallocate_image_memory(alloc); | 1380 | pages += pages_highmem; |
1348 | pages += pages_highmem; | 1381 | /* |
1382 | * size is the desired number of saveable pages to leave in | ||
1383 | * memory, so try to preallocate (all memory - size) pages. | ||
1384 | */ | ||
1385 | alloc = (count - pages) - size; | ||
1386 | pages += preallocate_image_highmem(alloc); | ||
1387 | } else { | ||
1388 | /* | ||
1389 | * There are approximately max_size saveable pages at this point | ||
1390 | * and we want to reduce this number down to size. | ||
1391 | */ | ||
1392 | alloc = max_size - size; | ||
1393 | size = preallocate_highmem_fraction(alloc, highmem, count); | ||
1394 | pages_highmem += size; | ||
1395 | alloc -= size; | ||
1396 | size = preallocate_image_memory(alloc, avail_normal); | ||
1397 | pages_highmem += preallocate_image_highmem(alloc - size); | ||
1398 | pages += pages_highmem + size; | ||
1399 | } | ||
1349 | 1400 | ||
1350 | /* | 1401 | /* |
1351 | * We only need as many page frames for the image as there are saveable | 1402 | * We only need as many page frames for the image as there are saveable |
@@ -1636,7 +1687,7 @@ int snapshot_read_next(struct snapshot_handle *handle) | |||
1636 | memory_bm_position_reset(&orig_bm); | 1687 | memory_bm_position_reset(&orig_bm); |
1637 | memory_bm_position_reset(©_bm); | 1688 | memory_bm_position_reset(©_bm); |
1638 | } else if (handle->cur <= nr_meta_pages) { | 1689 | } else if (handle->cur <= nr_meta_pages) { |
1639 | memset(buffer, 0, PAGE_SIZE); | 1690 | clear_page(buffer); |
1640 | pack_pfns(buffer, &orig_bm); | 1691 | pack_pfns(buffer, &orig_bm); |
1641 | } else { | 1692 | } else { |
1642 | struct page *page; | 1693 | struct page *page; |
@@ -1650,7 +1701,7 @@ int snapshot_read_next(struct snapshot_handle *handle) | |||
1650 | void *kaddr; | 1701 | void *kaddr; |
1651 | 1702 | ||
1652 | kaddr = kmap_atomic(page, KM_USER0); | 1703 | kaddr = kmap_atomic(page, KM_USER0); |
1653 | memcpy(buffer, kaddr, PAGE_SIZE); | 1704 | copy_page(buffer, kaddr); |
1654 | kunmap_atomic(kaddr, KM_USER0); | 1705 | kunmap_atomic(kaddr, KM_USER0); |
1655 | handle->buffer = buffer; | 1706 | handle->buffer = buffer; |
1656 | } else { | 1707 | } else { |
@@ -1933,7 +1984,7 @@ static void copy_last_highmem_page(void) | |||
1933 | void *dst; | 1984 | void *dst; |
1934 | 1985 | ||
1935 | dst = kmap_atomic(last_highmem_page, KM_USER0); | 1986 | dst = kmap_atomic(last_highmem_page, KM_USER0); |
1936 | memcpy(dst, buffer, PAGE_SIZE); | 1987 | copy_page(dst, buffer); |
1937 | kunmap_atomic(dst, KM_USER0); | 1988 | kunmap_atomic(dst, KM_USER0); |
1938 | last_highmem_page = NULL; | 1989 | last_highmem_page = NULL; |
1939 | } | 1990 | } |
@@ -2219,11 +2270,11 @@ swap_two_pages_data(struct page *p1, struct page *p2, void *buf) | |||
2219 | 2270 | ||
2220 | kaddr1 = kmap_atomic(p1, KM_USER0); | 2271 | kaddr1 = kmap_atomic(p1, KM_USER0); |
2221 | kaddr2 = kmap_atomic(p2, KM_USER1); | 2272 | kaddr2 = kmap_atomic(p2, KM_USER1); |
2222 | memcpy(buf, kaddr1, PAGE_SIZE); | 2273 | copy_page(buf, kaddr1); |
2223 | memcpy(kaddr1, kaddr2, PAGE_SIZE); | 2274 | copy_page(kaddr1, kaddr2); |
2224 | memcpy(kaddr2, buf, PAGE_SIZE); | 2275 | copy_page(kaddr2, buf); |
2225 | kunmap_atomic(kaddr1, KM_USER0); | ||
2226 | kunmap_atomic(kaddr2, KM_USER1); | 2276 | kunmap_atomic(kaddr2, KM_USER1); |
2277 | kunmap_atomic(kaddr1, KM_USER0); | ||
2227 | } | 2278 | } |
2228 | 2279 | ||
2229 | /** | 2280 | /** |
diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index 7335952ee473..ecf770509d0d 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c | |||
@@ -197,7 +197,6 @@ static int suspend_enter(suspend_state_t state) | |||
197 | int suspend_devices_and_enter(suspend_state_t state) | 197 | int suspend_devices_and_enter(suspend_state_t state) |
198 | { | 198 | { |
199 | int error; | 199 | int error; |
200 | gfp_t saved_mask; | ||
201 | 200 | ||
202 | if (!suspend_ops) | 201 | if (!suspend_ops) |
203 | return -ENOSYS; | 202 | return -ENOSYS; |
@@ -208,7 +207,7 @@ int suspend_devices_and_enter(suspend_state_t state) | |||
208 | goto Close; | 207 | goto Close; |
209 | } | 208 | } |
210 | suspend_console(); | 209 | suspend_console(); |
211 | saved_mask = clear_gfp_allowed_mask(GFP_IOFS); | 210 | pm_restrict_gfp_mask(); |
212 | suspend_test_start(); | 211 | suspend_test_start(); |
213 | error = dpm_suspend_start(PMSG_SUSPEND); | 212 | error = dpm_suspend_start(PMSG_SUSPEND); |
214 | if (error) { | 213 | if (error) { |
@@ -225,7 +224,7 @@ int suspend_devices_and_enter(suspend_state_t state) | |||
225 | suspend_test_start(); | 224 | suspend_test_start(); |
226 | dpm_resume_end(PMSG_RESUME); | 225 | dpm_resume_end(PMSG_RESUME); |
227 | suspend_test_finish("resume devices"); | 226 | suspend_test_finish("resume devices"); |
228 | set_gfp_allowed_mask(saved_mask); | 227 | pm_restore_gfp_mask(); |
229 | resume_console(); | 228 | resume_console(); |
230 | Close: | 229 | Close: |
231 | if (suspend_ops->end) | 230 | if (suspend_ops->end) |
diff --git a/kernel/power/swap.c b/kernel/power/swap.c index 5d0059eed3e4..8c7e4832b9be 100644 --- a/kernel/power/swap.c +++ b/kernel/power/swap.c | |||
@@ -6,6 +6,7 @@ | |||
6 | * | 6 | * |
7 | * Copyright (C) 1998,2001-2005 Pavel Machek <pavel@ucw.cz> | 7 | * Copyright (C) 1998,2001-2005 Pavel Machek <pavel@ucw.cz> |
8 | * Copyright (C) 2006 Rafael J. Wysocki <rjw@sisk.pl> | 8 | * Copyright (C) 2006 Rafael J. Wysocki <rjw@sisk.pl> |
9 | * Copyright (C) 2010 Bojan Smojver <bojan@rexursive.com> | ||
9 | * | 10 | * |
10 | * This file is released under the GPLv2. | 11 | * This file is released under the GPLv2. |
11 | * | 12 | * |
@@ -24,10 +25,12 @@ | |||
24 | #include <linux/swapops.h> | 25 | #include <linux/swapops.h> |
25 | #include <linux/pm.h> | 26 | #include <linux/pm.h> |
26 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
28 | #include <linux/lzo.h> | ||
29 | #include <linux/vmalloc.h> | ||
27 | 30 | ||
28 | #include "power.h" | 31 | #include "power.h" |
29 | 32 | ||
30 | #define SWSUSP_SIG "S1SUSPEND" | 33 | #define HIBERNATE_SIG "S1SUSPEND" |
31 | 34 | ||
32 | /* | 35 | /* |
33 | * The swap map is a data structure used for keeping track of each page | 36 | * The swap map is a data structure used for keeping track of each page |
@@ -136,10 +139,10 @@ sector_t alloc_swapdev_block(int swap) | |||
136 | { | 139 | { |
137 | unsigned long offset; | 140 | unsigned long offset; |
138 | 141 | ||
139 | offset = swp_offset(get_swap_for_hibernation(swap)); | 142 | offset = swp_offset(get_swap_page_of_type(swap)); |
140 | if (offset) { | 143 | if (offset) { |
141 | if (swsusp_extents_insert(offset)) | 144 | if (swsusp_extents_insert(offset)) |
142 | swap_free_for_hibernation(swp_entry(swap, offset)); | 145 | swap_free(swp_entry(swap, offset)); |
143 | else | 146 | else |
144 | return swapdev_block(swap, offset); | 147 | return swapdev_block(swap, offset); |
145 | } | 148 | } |
@@ -163,7 +166,7 @@ void free_all_swap_pages(int swap) | |||
163 | ext = container_of(node, struct swsusp_extent, node); | 166 | ext = container_of(node, struct swsusp_extent, node); |
164 | rb_erase(node, &swsusp_extents); | 167 | rb_erase(node, &swsusp_extents); |
165 | for (offset = ext->start; offset <= ext->end; offset++) | 168 | for (offset = ext->start; offset <= ext->end; offset++) |
166 | swap_free_for_hibernation(swp_entry(swap, offset)); | 169 | swap_free(swp_entry(swap, offset)); |
167 | 170 | ||
168 | kfree(ext); | 171 | kfree(ext); |
169 | } | 172 | } |
@@ -193,7 +196,7 @@ static int mark_swapfiles(struct swap_map_handle *handle, unsigned int flags) | |||
193 | if (!memcmp("SWAP-SPACE",swsusp_header->sig, 10) || | 196 | if (!memcmp("SWAP-SPACE",swsusp_header->sig, 10) || |
194 | !memcmp("SWAPSPACE2",swsusp_header->sig, 10)) { | 197 | !memcmp("SWAPSPACE2",swsusp_header->sig, 10)) { |
195 | memcpy(swsusp_header->orig_sig,swsusp_header->sig, 10); | 198 | memcpy(swsusp_header->orig_sig,swsusp_header->sig, 10); |
196 | memcpy(swsusp_header->sig,SWSUSP_SIG, 10); | 199 | memcpy(swsusp_header->sig, HIBERNATE_SIG, 10); |
197 | swsusp_header->image = handle->first_sector; | 200 | swsusp_header->image = handle->first_sector; |
198 | swsusp_header->flags = flags; | 201 | swsusp_header->flags = flags; |
199 | error = hib_bio_write_page(swsusp_resume_block, | 202 | error = hib_bio_write_page(swsusp_resume_block, |
@@ -249,7 +252,7 @@ static int write_page(void *buf, sector_t offset, struct bio **bio_chain) | |||
249 | if (bio_chain) { | 252 | if (bio_chain) { |
250 | src = (void *)__get_free_page(__GFP_WAIT | __GFP_HIGH); | 253 | src = (void *)__get_free_page(__GFP_WAIT | __GFP_HIGH); |
251 | if (src) { | 254 | if (src) { |
252 | memcpy(src, buf, PAGE_SIZE); | 255 | copy_page(src, buf); |
253 | } else { | 256 | } else { |
254 | WARN_ON_ONCE(1); | 257 | WARN_ON_ONCE(1); |
255 | bio_chain = NULL; /* Go synchronous */ | 258 | bio_chain = NULL; /* Go synchronous */ |
@@ -323,7 +326,7 @@ static int swap_write_page(struct swap_map_handle *handle, void *buf, | |||
323 | error = write_page(handle->cur, handle->cur_swap, NULL); | 326 | error = write_page(handle->cur, handle->cur_swap, NULL); |
324 | if (error) | 327 | if (error) |
325 | goto out; | 328 | goto out; |
326 | memset(handle->cur, 0, PAGE_SIZE); | 329 | clear_page(handle->cur); |
327 | handle->cur_swap = offset; | 330 | handle->cur_swap = offset; |
328 | handle->k = 0; | 331 | handle->k = 0; |
329 | } | 332 | } |
@@ -357,6 +360,18 @@ static int swap_writer_finish(struct swap_map_handle *handle, | |||
357 | return error; | 360 | return error; |
358 | } | 361 | } |
359 | 362 | ||
363 | /* We need to remember how much compressed data we need to read. */ | ||
364 | #define LZO_HEADER sizeof(size_t) | ||
365 | |||
366 | /* Number of pages/bytes we'll compress at one time. */ | ||
367 | #define LZO_UNC_PAGES 32 | ||
368 | #define LZO_UNC_SIZE (LZO_UNC_PAGES * PAGE_SIZE) | ||
369 | |||
370 | /* Number of pages/bytes we need for compressed data (worst case). */ | ||
371 | #define LZO_CMP_PAGES DIV_ROUND_UP(lzo1x_worst_compress(LZO_UNC_SIZE) + \ | ||
372 | LZO_HEADER, PAGE_SIZE) | ||
373 | #define LZO_CMP_SIZE (LZO_CMP_PAGES * PAGE_SIZE) | ||
374 | |||
360 | /** | 375 | /** |
361 | * save_image - save the suspend image data | 376 | * save_image - save the suspend image data |
362 | */ | 377 | */ |
@@ -404,6 +419,137 @@ static int save_image(struct swap_map_handle *handle, | |||
404 | return ret; | 419 | return ret; |
405 | } | 420 | } |
406 | 421 | ||
422 | |||
423 | /** | ||
424 | * save_image_lzo - Save the suspend image data compressed with LZO. | ||
425 | * @handle: Swap mam handle to use for saving the image. | ||
426 | * @snapshot: Image to read data from. | ||
427 | * @nr_to_write: Number of pages to save. | ||
428 | */ | ||
429 | static int save_image_lzo(struct swap_map_handle *handle, | ||
430 | struct snapshot_handle *snapshot, | ||
431 | unsigned int nr_to_write) | ||
432 | { | ||
433 | unsigned int m; | ||
434 | int ret = 0; | ||
435 | int nr_pages; | ||
436 | int err2; | ||
437 | struct bio *bio; | ||
438 | struct timeval start; | ||
439 | struct timeval stop; | ||
440 | size_t off, unc_len, cmp_len; | ||
441 | unsigned char *unc, *cmp, *wrk, *page; | ||
442 | |||
443 | page = (void *)__get_free_page(__GFP_WAIT | __GFP_HIGH); | ||
444 | if (!page) { | ||
445 | printk(KERN_ERR "PM: Failed to allocate LZO page\n"); | ||
446 | return -ENOMEM; | ||
447 | } | ||
448 | |||
449 | wrk = vmalloc(LZO1X_1_MEM_COMPRESS); | ||
450 | if (!wrk) { | ||
451 | printk(KERN_ERR "PM: Failed to allocate LZO workspace\n"); | ||
452 | free_page((unsigned long)page); | ||
453 | return -ENOMEM; | ||
454 | } | ||
455 | |||
456 | unc = vmalloc(LZO_UNC_SIZE); | ||
457 | if (!unc) { | ||
458 | printk(KERN_ERR "PM: Failed to allocate LZO uncompressed\n"); | ||
459 | vfree(wrk); | ||
460 | free_page((unsigned long)page); | ||
461 | return -ENOMEM; | ||
462 | } | ||
463 | |||
464 | cmp = vmalloc(LZO_CMP_SIZE); | ||
465 | if (!cmp) { | ||
466 | printk(KERN_ERR "PM: Failed to allocate LZO compressed\n"); | ||
467 | vfree(unc); | ||
468 | vfree(wrk); | ||
469 | free_page((unsigned long)page); | ||
470 | return -ENOMEM; | ||
471 | } | ||
472 | |||
473 | printk(KERN_INFO | ||
474 | "PM: Compressing and saving image data (%u pages) ... ", | ||
475 | nr_to_write); | ||
476 | m = nr_to_write / 100; | ||
477 | if (!m) | ||
478 | m = 1; | ||
479 | nr_pages = 0; | ||
480 | bio = NULL; | ||
481 | do_gettimeofday(&start); | ||
482 | for (;;) { | ||
483 | for (off = 0; off < LZO_UNC_SIZE; off += PAGE_SIZE) { | ||
484 | ret = snapshot_read_next(snapshot); | ||
485 | if (ret < 0) | ||
486 | goto out_finish; | ||
487 | |||
488 | if (!ret) | ||
489 | break; | ||
490 | |||
491 | memcpy(unc + off, data_of(*snapshot), PAGE_SIZE); | ||
492 | |||
493 | if (!(nr_pages % m)) | ||
494 | printk(KERN_CONT "\b\b\b\b%3d%%", nr_pages / m); | ||
495 | nr_pages++; | ||
496 | } | ||
497 | |||
498 | if (!off) | ||
499 | break; | ||
500 | |||
501 | unc_len = off; | ||
502 | ret = lzo1x_1_compress(unc, unc_len, | ||
503 | cmp + LZO_HEADER, &cmp_len, wrk); | ||
504 | if (ret < 0) { | ||
505 | printk(KERN_ERR "PM: LZO compression failed\n"); | ||
506 | break; | ||
507 | } | ||
508 | |||
509 | if (unlikely(!cmp_len || | ||
510 | cmp_len > lzo1x_worst_compress(unc_len))) { | ||
511 | printk(KERN_ERR "PM: Invalid LZO compressed length\n"); | ||
512 | ret = -1; | ||
513 | break; | ||
514 | } | ||
515 | |||
516 | *(size_t *)cmp = cmp_len; | ||
517 | |||
518 | /* | ||
519 | * Given we are writing one page at a time to disk, we copy | ||
520 | * that much from the buffer, although the last bit will likely | ||
521 | * be smaller than full page. This is OK - we saved the length | ||
522 | * of the compressed data, so any garbage at the end will be | ||
523 | * discarded when we read it. | ||
524 | */ | ||
525 | for (off = 0; off < LZO_HEADER + cmp_len; off += PAGE_SIZE) { | ||
526 | memcpy(page, cmp + off, PAGE_SIZE); | ||
527 | |||
528 | ret = swap_write_page(handle, page, &bio); | ||
529 | if (ret) | ||
530 | goto out_finish; | ||
531 | } | ||
532 | } | ||
533 | |||
534 | out_finish: | ||
535 | err2 = hib_wait_on_bio_chain(&bio); | ||
536 | do_gettimeofday(&stop); | ||
537 | if (!ret) | ||
538 | ret = err2; | ||
539 | if (!ret) | ||
540 | printk(KERN_CONT "\b\b\b\bdone\n"); | ||
541 | else | ||
542 | printk(KERN_CONT "\n"); | ||
543 | swsusp_show_speed(&start, &stop, nr_to_write, "Wrote"); | ||
544 | |||
545 | vfree(cmp); | ||
546 | vfree(unc); | ||
547 | vfree(wrk); | ||
548 | free_page((unsigned long)page); | ||
549 | |||
550 | return ret; | ||
551 | } | ||
552 | |||
407 | /** | 553 | /** |
408 | * enough_swap - Make sure we have enough swap to save the image. | 554 | * enough_swap - Make sure we have enough swap to save the image. |
409 | * | 555 | * |
@@ -411,12 +557,16 @@ static int save_image(struct swap_map_handle *handle, | |||
411 | * space avaiable from the resume partition. | 557 | * space avaiable from the resume partition. |
412 | */ | 558 | */ |
413 | 559 | ||
414 | static int enough_swap(unsigned int nr_pages) | 560 | static int enough_swap(unsigned int nr_pages, unsigned int flags) |
415 | { | 561 | { |
416 | unsigned int free_swap = count_swap_pages(root_swap, 1); | 562 | unsigned int free_swap = count_swap_pages(root_swap, 1); |
563 | unsigned int required; | ||
417 | 564 | ||
418 | pr_debug("PM: Free swap pages: %u\n", free_swap); | 565 | pr_debug("PM: Free swap pages: %u\n", free_swap); |
419 | return free_swap > nr_pages + PAGES_FOR_IO; | 566 | |
567 | required = PAGES_FOR_IO + ((flags & SF_NOCOMPRESS_MODE) ? | ||
568 | nr_pages : (nr_pages * LZO_CMP_PAGES) / LZO_UNC_PAGES + 1); | ||
569 | return free_swap > required; | ||
420 | } | 570 | } |
421 | 571 | ||
422 | /** | 572 | /** |
@@ -443,7 +593,7 @@ int swsusp_write(unsigned int flags) | |||
443 | printk(KERN_ERR "PM: Cannot get swap writer\n"); | 593 | printk(KERN_ERR "PM: Cannot get swap writer\n"); |
444 | return error; | 594 | return error; |
445 | } | 595 | } |
446 | if (!enough_swap(pages)) { | 596 | if (!enough_swap(pages, flags)) { |
447 | printk(KERN_ERR "PM: Not enough free swap\n"); | 597 | printk(KERN_ERR "PM: Not enough free swap\n"); |
448 | error = -ENOSPC; | 598 | error = -ENOSPC; |
449 | goto out_finish; | 599 | goto out_finish; |
@@ -458,8 +608,11 @@ int swsusp_write(unsigned int flags) | |||
458 | } | 608 | } |
459 | header = (struct swsusp_info *)data_of(snapshot); | 609 | header = (struct swsusp_info *)data_of(snapshot); |
460 | error = swap_write_page(&handle, header, NULL); | 610 | error = swap_write_page(&handle, header, NULL); |
461 | if (!error) | 611 | if (!error) { |
462 | error = save_image(&handle, &snapshot, pages - 1); | 612 | error = (flags & SF_NOCOMPRESS_MODE) ? |
613 | save_image(&handle, &snapshot, pages - 1) : | ||
614 | save_image_lzo(&handle, &snapshot, pages - 1); | ||
615 | } | ||
463 | out_finish: | 616 | out_finish: |
464 | error = swap_writer_finish(&handle, flags, error); | 617 | error = swap_writer_finish(&handle, flags, error); |
465 | return error; | 618 | return error; |
@@ -590,6 +743,149 @@ static int load_image(struct swap_map_handle *handle, | |||
590 | } | 743 | } |
591 | 744 | ||
592 | /** | 745 | /** |
746 | * load_image_lzo - Load compressed image data and decompress them with LZO. | ||
747 | * @handle: Swap map handle to use for loading data. | ||
748 | * @snapshot: Image to copy uncompressed data into. | ||
749 | * @nr_to_read: Number of pages to load. | ||
750 | */ | ||
751 | static int load_image_lzo(struct swap_map_handle *handle, | ||
752 | struct snapshot_handle *snapshot, | ||
753 | unsigned int nr_to_read) | ||
754 | { | ||
755 | unsigned int m; | ||
756 | int error = 0; | ||
757 | struct bio *bio; | ||
758 | struct timeval start; | ||
759 | struct timeval stop; | ||
760 | unsigned nr_pages; | ||
761 | size_t i, off, unc_len, cmp_len; | ||
762 | unsigned char *unc, *cmp, *page[LZO_CMP_PAGES]; | ||
763 | |||
764 | for (i = 0; i < LZO_CMP_PAGES; i++) { | ||
765 | page[i] = (void *)__get_free_page(__GFP_WAIT | __GFP_HIGH); | ||
766 | if (!page[i]) { | ||
767 | printk(KERN_ERR "PM: Failed to allocate LZO page\n"); | ||
768 | |||
769 | while (i) | ||
770 | free_page((unsigned long)page[--i]); | ||
771 | |||
772 | return -ENOMEM; | ||
773 | } | ||
774 | } | ||
775 | |||
776 | unc = vmalloc(LZO_UNC_SIZE); | ||
777 | if (!unc) { | ||
778 | printk(KERN_ERR "PM: Failed to allocate LZO uncompressed\n"); | ||
779 | |||
780 | for (i = 0; i < LZO_CMP_PAGES; i++) | ||
781 | free_page((unsigned long)page[i]); | ||
782 | |||
783 | return -ENOMEM; | ||
784 | } | ||
785 | |||
786 | cmp = vmalloc(LZO_CMP_SIZE); | ||
787 | if (!cmp) { | ||
788 | printk(KERN_ERR "PM: Failed to allocate LZO compressed\n"); | ||
789 | |||
790 | vfree(unc); | ||
791 | for (i = 0; i < LZO_CMP_PAGES; i++) | ||
792 | free_page((unsigned long)page[i]); | ||
793 | |||
794 | return -ENOMEM; | ||
795 | } | ||
796 | |||
797 | printk(KERN_INFO | ||
798 | "PM: Loading and decompressing image data (%u pages) ... ", | ||
799 | nr_to_read); | ||
800 | m = nr_to_read / 100; | ||
801 | if (!m) | ||
802 | m = 1; | ||
803 | nr_pages = 0; | ||
804 | bio = NULL; | ||
805 | do_gettimeofday(&start); | ||
806 | |||
807 | error = snapshot_write_next(snapshot); | ||
808 | if (error <= 0) | ||
809 | goto out_finish; | ||
810 | |||
811 | for (;;) { | ||
812 | error = swap_read_page(handle, page[0], NULL); /* sync */ | ||
813 | if (error) | ||
814 | break; | ||
815 | |||
816 | cmp_len = *(size_t *)page[0]; | ||
817 | if (unlikely(!cmp_len || | ||
818 | cmp_len > lzo1x_worst_compress(LZO_UNC_SIZE))) { | ||
819 | printk(KERN_ERR "PM: Invalid LZO compressed length\n"); | ||
820 | error = -1; | ||
821 | break; | ||
822 | } | ||
823 | |||
824 | for (off = PAGE_SIZE, i = 1; | ||
825 | off < LZO_HEADER + cmp_len; off += PAGE_SIZE, i++) { | ||
826 | error = swap_read_page(handle, page[i], &bio); | ||
827 | if (error) | ||
828 | goto out_finish; | ||
829 | } | ||
830 | |||
831 | error = hib_wait_on_bio_chain(&bio); /* need all data now */ | ||
832 | if (error) | ||
833 | goto out_finish; | ||
834 | |||
835 | for (off = 0, i = 0; | ||
836 | off < LZO_HEADER + cmp_len; off += PAGE_SIZE, i++) { | ||
837 | memcpy(cmp + off, page[i], PAGE_SIZE); | ||
838 | } | ||
839 | |||
840 | unc_len = LZO_UNC_SIZE; | ||
841 | error = lzo1x_decompress_safe(cmp + LZO_HEADER, cmp_len, | ||
842 | unc, &unc_len); | ||
843 | if (error < 0) { | ||
844 | printk(KERN_ERR "PM: LZO decompression failed\n"); | ||
845 | break; | ||
846 | } | ||
847 | |||
848 | if (unlikely(!unc_len || | ||
849 | unc_len > LZO_UNC_SIZE || | ||
850 | unc_len & (PAGE_SIZE - 1))) { | ||
851 | printk(KERN_ERR "PM: Invalid LZO uncompressed length\n"); | ||
852 | error = -1; | ||
853 | break; | ||
854 | } | ||
855 | |||
856 | for (off = 0; off < unc_len; off += PAGE_SIZE) { | ||
857 | memcpy(data_of(*snapshot), unc + off, PAGE_SIZE); | ||
858 | |||
859 | if (!(nr_pages % m)) | ||
860 | printk("\b\b\b\b%3d%%", nr_pages / m); | ||
861 | nr_pages++; | ||
862 | |||
863 | error = snapshot_write_next(snapshot); | ||
864 | if (error <= 0) | ||
865 | goto out_finish; | ||
866 | } | ||
867 | } | ||
868 | |||
869 | out_finish: | ||
870 | do_gettimeofday(&stop); | ||
871 | if (!error) { | ||
872 | printk("\b\b\b\bdone\n"); | ||
873 | snapshot_write_finalize(snapshot); | ||
874 | if (!snapshot_image_loaded(snapshot)) | ||
875 | error = -ENODATA; | ||
876 | } else | ||
877 | printk("\n"); | ||
878 | swsusp_show_speed(&start, &stop, nr_to_read, "Read"); | ||
879 | |||
880 | vfree(cmp); | ||
881 | vfree(unc); | ||
882 | for (i = 0; i < LZO_CMP_PAGES; i++) | ||
883 | free_page((unsigned long)page[i]); | ||
884 | |||
885 | return error; | ||
886 | } | ||
887 | |||
888 | /** | ||
593 | * swsusp_read - read the hibernation image. | 889 | * swsusp_read - read the hibernation image. |
594 | * @flags_p: flags passed by the "frozen" kernel in the image header should | 890 | * @flags_p: flags passed by the "frozen" kernel in the image header should |
595 | * be written into this memeory location | 891 | * be written into this memeory location |
@@ -612,8 +908,11 @@ int swsusp_read(unsigned int *flags_p) | |||
612 | goto end; | 908 | goto end; |
613 | if (!error) | 909 | if (!error) |
614 | error = swap_read_page(&handle, header, NULL); | 910 | error = swap_read_page(&handle, header, NULL); |
615 | if (!error) | 911 | if (!error) { |
616 | error = load_image(&handle, &snapshot, header->pages - 1); | 912 | error = (*flags_p & SF_NOCOMPRESS_MODE) ? |
913 | load_image(&handle, &snapshot, header->pages - 1) : | ||
914 | load_image_lzo(&handle, &snapshot, header->pages - 1); | ||
915 | } | ||
617 | swap_reader_finish(&handle); | 916 | swap_reader_finish(&handle); |
618 | end: | 917 | end: |
619 | if (!error) | 918 | if (!error) |
@@ -634,13 +933,13 @@ int swsusp_check(void) | |||
634 | hib_resume_bdev = open_by_devnum(swsusp_resume_device, FMODE_READ); | 933 | hib_resume_bdev = open_by_devnum(swsusp_resume_device, FMODE_READ); |
635 | if (!IS_ERR(hib_resume_bdev)) { | 934 | if (!IS_ERR(hib_resume_bdev)) { |
636 | set_blocksize(hib_resume_bdev, PAGE_SIZE); | 935 | set_blocksize(hib_resume_bdev, PAGE_SIZE); |
637 | memset(swsusp_header, 0, PAGE_SIZE); | 936 | clear_page(swsusp_header); |
638 | error = hib_bio_read_page(swsusp_resume_block, | 937 | error = hib_bio_read_page(swsusp_resume_block, |
639 | swsusp_header, NULL); | 938 | swsusp_header, NULL); |
640 | if (error) | 939 | if (error) |
641 | goto put; | 940 | goto put; |
642 | 941 | ||
643 | if (!memcmp(SWSUSP_SIG, swsusp_header->sig, 10)) { | 942 | if (!memcmp(HIBERNATE_SIG, swsusp_header->sig, 10)) { |
644 | memcpy(swsusp_header->sig, swsusp_header->orig_sig, 10); | 943 | memcpy(swsusp_header->sig, swsusp_header->orig_sig, 10); |
645 | /* Reset swap signature now */ | 944 | /* Reset swap signature now */ |
646 | error = hib_bio_write_page(swsusp_resume_block, | 945 | error = hib_bio_write_page(swsusp_resume_block, |
@@ -653,13 +952,13 @@ put: | |||
653 | if (error) | 952 | if (error) |
654 | blkdev_put(hib_resume_bdev, FMODE_READ); | 953 | blkdev_put(hib_resume_bdev, FMODE_READ); |
655 | else | 954 | else |
656 | pr_debug("PM: Signature found, resuming\n"); | 955 | pr_debug("PM: Image signature found, resuming\n"); |
657 | } else { | 956 | } else { |
658 | error = PTR_ERR(hib_resume_bdev); | 957 | error = PTR_ERR(hib_resume_bdev); |
659 | } | 958 | } |
660 | 959 | ||
661 | if (error) | 960 | if (error) |
662 | pr_debug("PM: Error %d checking image file\n", error); | 961 | pr_debug("PM: Image not found (code %d)\n", error); |
663 | 962 | ||
664 | return error; | 963 | return error; |
665 | } | 964 | } |
diff --git a/kernel/power/user.c b/kernel/power/user.c index e819e17877ca..c36c3b9e8a84 100644 --- a/kernel/power/user.c +++ b/kernel/power/user.c | |||
@@ -137,7 +137,7 @@ static int snapshot_release(struct inode *inode, struct file *filp) | |||
137 | free_all_swap_pages(data->swap); | 137 | free_all_swap_pages(data->swap); |
138 | if (data->frozen) | 138 | if (data->frozen) |
139 | thaw_processes(); | 139 | thaw_processes(); |
140 | pm_notifier_call_chain(data->mode == O_WRONLY ? | 140 | pm_notifier_call_chain(data->mode == O_RDONLY ? |
141 | PM_POST_HIBERNATION : PM_POST_RESTORE); | 141 | PM_POST_HIBERNATION : PM_POST_RESTORE); |
142 | atomic_inc(&snapshot_device_available); | 142 | atomic_inc(&snapshot_device_available); |
143 | 143 | ||
@@ -263,6 +263,7 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd, | |||
263 | case SNAPSHOT_UNFREEZE: | 263 | case SNAPSHOT_UNFREEZE: |
264 | if (!data->frozen || data->ready) | 264 | if (!data->frozen || data->ready) |
265 | break; | 265 | break; |
266 | pm_restore_gfp_mask(); | ||
266 | thaw_processes(); | 267 | thaw_processes(); |
267 | usermodehelper_enable(); | 268 | usermodehelper_enable(); |
268 | data->frozen = 0; | 269 | data->frozen = 0; |
@@ -275,6 +276,7 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd, | |||
275 | error = -EPERM; | 276 | error = -EPERM; |
276 | break; | 277 | break; |
277 | } | 278 | } |
279 | pm_restore_gfp_mask(); | ||
278 | error = hibernation_snapshot(data->platform_support); | 280 | error = hibernation_snapshot(data->platform_support); |
279 | if (!error) | 281 | if (!error) |
280 | error = put_user(in_suspend, (int __user *)arg); | 282 | error = put_user(in_suspend, (int __user *)arg); |