diff options
-rw-r--r-- | kernel/power/hibernate.c | 65 | ||||
-rw-r--r-- | kernel/power/swap.c | 6 |
2 files changed, 50 insertions, 21 deletions
diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c index 5f3523e18e46..0ee1df0a0bd6 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c | |||
@@ -52,6 +52,7 @@ enum { | |||
52 | #ifdef CONFIG_SUSPEND | 52 | #ifdef CONFIG_SUSPEND |
53 | HIBERNATION_SUSPEND, | 53 | HIBERNATION_SUSPEND, |
54 | #endif | 54 | #endif |
55 | HIBERNATION_TEST_RESUME, | ||
55 | /* keep last */ | 56 | /* keep last */ |
56 | __HIBERNATION_AFTER_LAST | 57 | __HIBERNATION_AFTER_LAST |
57 | }; | 58 | }; |
@@ -647,12 +648,39 @@ static void power_down(void) | |||
647 | cpu_relax(); | 648 | cpu_relax(); |
648 | } | 649 | } |
649 | 650 | ||
651 | static int load_image_and_restore(void) | ||
652 | { | ||
653 | int error; | ||
654 | unsigned int flags; | ||
655 | |||
656 | pr_debug("PM: Loading hibernation image.\n"); | ||
657 | |||
658 | lock_device_hotplug(); | ||
659 | error = create_basic_memory_bitmaps(); | ||
660 | if (error) | ||
661 | goto Unlock; | ||
662 | |||
663 | error = swsusp_read(&flags); | ||
664 | swsusp_close(FMODE_READ); | ||
665 | if (!error) | ||
666 | hibernation_restore(flags & SF_PLATFORM_MODE); | ||
667 | |||
668 | printk(KERN_ERR "PM: Failed to load hibernation image, recovering.\n"); | ||
669 | swsusp_free(); | ||
670 | free_basic_memory_bitmaps(); | ||
671 | Unlock: | ||
672 | unlock_device_hotplug(); | ||
673 | |||
674 | return error; | ||
675 | } | ||
676 | |||
650 | /** | 677 | /** |
651 | * hibernate - Carry out system hibernation, including saving the image. | 678 | * hibernate - Carry out system hibernation, including saving the image. |
652 | */ | 679 | */ |
653 | int hibernate(void) | 680 | int hibernate(void) |
654 | { | 681 | { |
655 | int error, nr_calls = 0; | 682 | int error, nr_calls = 0; |
683 | bool snapshot_test = false; | ||
656 | 684 | ||
657 | if (!hibernation_available()) { | 685 | if (!hibernation_available()) { |
658 | pr_debug("PM: Hibernation not available.\n"); | 686 | pr_debug("PM: Hibernation not available.\n"); |
@@ -704,8 +732,12 @@ int hibernate(void) | |||
704 | pr_debug("PM: writing image.\n"); | 732 | pr_debug("PM: writing image.\n"); |
705 | error = swsusp_write(flags); | 733 | error = swsusp_write(flags); |
706 | swsusp_free(); | 734 | swsusp_free(); |
707 | if (!error) | 735 | if (!error) { |
708 | power_down(); | 736 | if (hibernation_mode == HIBERNATION_TEST_RESUME) |
737 | snapshot_test = true; | ||
738 | else | ||
739 | power_down(); | ||
740 | } | ||
709 | in_suspend = 0; | 741 | in_suspend = 0; |
710 | pm_restore_gfp_mask(); | 742 | pm_restore_gfp_mask(); |
711 | } else { | 743 | } else { |
@@ -716,6 +748,12 @@ int hibernate(void) | |||
716 | free_basic_memory_bitmaps(); | 748 | free_basic_memory_bitmaps(); |
717 | Thaw: | 749 | Thaw: |
718 | unlock_device_hotplug(); | 750 | unlock_device_hotplug(); |
751 | if (snapshot_test) { | ||
752 | pr_debug("PM: Checking hibernation image\n"); | ||
753 | error = swsusp_check(); | ||
754 | if (!error) | ||
755 | error = load_image_and_restore(); | ||
756 | } | ||
719 | thaw_processes(); | 757 | thaw_processes(); |
720 | 758 | ||
721 | /* Don't bother checking whether freezer_test_done is true */ | 759 | /* Don't bother checking whether freezer_test_done is true */ |
@@ -748,7 +786,6 @@ int hibernate(void) | |||
748 | static int software_resume(void) | 786 | static int software_resume(void) |
749 | { | 787 | { |
750 | int error, nr_calls = 0; | 788 | int error, nr_calls = 0; |
751 | unsigned int flags; | ||
752 | 789 | ||
753 | /* | 790 | /* |
754 | * If the user said "noresume".. bail out early. | 791 | * If the user said "noresume".. bail out early. |
@@ -844,24 +881,7 @@ static int software_resume(void) | |||
844 | error = freeze_processes(); | 881 | error = freeze_processes(); |
845 | if (error) | 882 | if (error) |
846 | goto Close_Finish; | 883 | goto Close_Finish; |
847 | 884 | error = load_image_and_restore(); | |
848 | pr_debug("PM: Loading hibernation image.\n"); | ||
849 | |||
850 | lock_device_hotplug(); | ||
851 | error = create_basic_memory_bitmaps(); | ||
852 | if (error) | ||
853 | goto Thaw; | ||
854 | |||
855 | error = swsusp_read(&flags); | ||
856 | swsusp_close(FMODE_READ); | ||
857 | if (!error) | ||
858 | hibernation_restore(flags & SF_PLATFORM_MODE); | ||
859 | |||
860 | printk(KERN_ERR "PM: Failed to load hibernation image, recovering.\n"); | ||
861 | swsusp_free(); | ||
862 | free_basic_memory_bitmaps(); | ||
863 | Thaw: | ||
864 | unlock_device_hotplug(); | ||
865 | thaw_processes(); | 885 | thaw_processes(); |
866 | Finish: | 886 | Finish: |
867 | __pm_notifier_call_chain(PM_POST_RESTORE, nr_calls, NULL); | 887 | __pm_notifier_call_chain(PM_POST_RESTORE, nr_calls, NULL); |
@@ -887,6 +907,7 @@ static const char * const hibernation_modes[] = { | |||
887 | #ifdef CONFIG_SUSPEND | 907 | #ifdef CONFIG_SUSPEND |
888 | [HIBERNATION_SUSPEND] = "suspend", | 908 | [HIBERNATION_SUSPEND] = "suspend", |
889 | #endif | 909 | #endif |
910 | [HIBERNATION_TEST_RESUME] = "test_resume", | ||
890 | }; | 911 | }; |
891 | 912 | ||
892 | /* | 913 | /* |
@@ -933,6 +954,7 @@ static ssize_t disk_show(struct kobject *kobj, struct kobj_attribute *attr, | |||
933 | #ifdef CONFIG_SUSPEND | 954 | #ifdef CONFIG_SUSPEND |
934 | case HIBERNATION_SUSPEND: | 955 | case HIBERNATION_SUSPEND: |
935 | #endif | 956 | #endif |
957 | case HIBERNATION_TEST_RESUME: | ||
936 | break; | 958 | break; |
937 | case HIBERNATION_PLATFORM: | 959 | case HIBERNATION_PLATFORM: |
938 | if (hibernation_ops) | 960 | if (hibernation_ops) |
@@ -979,6 +1001,7 @@ static ssize_t disk_store(struct kobject *kobj, struct kobj_attribute *attr, | |||
979 | #ifdef CONFIG_SUSPEND | 1001 | #ifdef CONFIG_SUSPEND |
980 | case HIBERNATION_SUSPEND: | 1002 | case HIBERNATION_SUSPEND: |
981 | #endif | 1003 | #endif |
1004 | case HIBERNATION_TEST_RESUME: | ||
982 | hibernation_mode = mode; | 1005 | hibernation_mode = mode; |
983 | break; | 1006 | break; |
984 | case HIBERNATION_PLATFORM: | 1007 | case HIBERNATION_PLATFORM: |
diff --git a/kernel/power/swap.c b/kernel/power/swap.c index 160e1006640d..51cef8432154 100644 --- a/kernel/power/swap.c +++ b/kernel/power/swap.c | |||
@@ -348,6 +348,12 @@ static int swsusp_swap_check(void) | |||
348 | if (res < 0) | 348 | if (res < 0) |
349 | blkdev_put(hib_resume_bdev, FMODE_WRITE); | 349 | blkdev_put(hib_resume_bdev, FMODE_WRITE); |
350 | 350 | ||
351 | /* | ||
352 | * Update the resume device to the one actually used, | ||
353 | * so the test_resume mode can use it in case it is | ||
354 | * invoked from hibernate() to test the snapshot. | ||
355 | */ | ||
356 | swsusp_resume_device = hib_resume_bdev->bd_dev; | ||
351 | return res; | 357 | return res; |
352 | } | 358 | } |
353 | 359 | ||