aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorChen Yu <yu.c.chen@intel.com>2016-07-21 22:30:47 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2016-07-22 07:57:23 -0400
commitfe12c00d21bb4985fa8da282942250be21e7dd59 (patch)
tree35231867af10de4803b883b43e924ae785ee7faf /kernel
parent406f992e4a372dafbe3c2cff7efbb2002a5c8ebd (diff)
PM / hibernate: Introduce test_resume mode for hibernation
test_resume mode is to verify if the snapshot data written to swap device can be successfully restored to memory. It is useful to ease the debugging process on hibernation, since this mode can not only bypass the BIOSes/bootloader, but also the system re-initialization. To avoid the risk to break the filesystm on persistent storage, this patch resumes the image with tasks frozen. For example: echo test_resume > /sys/power/disk echo disk > /sys/power/state [ 187.306470] PM: Image saving progress: 70% [ 187.395298] PM: Image saving progress: 80% [ 187.476697] PM: Image saving progress: 90% [ 187.554641] PM: Image saving done. [ 187.558896] PM: Wrote 594600 kbytes in 0.90 seconds (660.66 MB/s) [ 187.566000] PM: S| [ 187.589742] PM: Basic memory bitmaps freed [ 187.594694] PM: Checking hibernation image [ 187.599865] PM: Image signature found, resuming [ 187.605209] PM: Loading hibernation image. [ 187.665753] PM: Basic memory bitmaps created [ 187.691397] PM: Using 3 thread(s) for decompression. [ 187.691397] PM: Loading and decompressing image data (148650 pages)... [ 187.889719] PM: Image loading progress: 0% [ 188.100452] PM: Image loading progress: 10% [ 188.244781] PM: Image loading progress: 20% [ 189.057305] PM: Image loading done. [ 189.068793] PM: Image successfully loaded Suggested-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Signed-off-by: Chen Yu <yu.c.chen@intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/power/hibernate.c65
-rw-r--r--kernel/power/swap.c6
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
651static 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 */
653int hibernate(void) 680int 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)
748static int software_resume(void) 786static 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