.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * kernel/power/hibernate.c - Hibernation (a.k.a suspend-to-disk) support. |
---|
3 | 4 | * |
---|
.. | .. |
---|
6 | 7 | * Copyright (c) 2004 Pavel Machek <pavel@ucw.cz> |
---|
7 | 8 | * Copyright (c) 2009 Rafael J. Wysocki, Novell Inc. |
---|
8 | 9 | * Copyright (C) 2012 Bojan Smojver <bojan@rexursive.com> |
---|
9 | | - * |
---|
10 | | - * This file is released under the GPLv2. |
---|
11 | 10 | */ |
---|
12 | 11 | |
---|
13 | | -#define pr_fmt(fmt) "PM: " fmt |
---|
| 12 | +#define pr_fmt(fmt) "PM: hibernation: " fmt |
---|
14 | 13 | |
---|
15 | 14 | #include <linux/export.h> |
---|
16 | 15 | #include <linux/suspend.h> |
---|
17 | | -#include <linux/syscalls.h> |
---|
18 | 16 | #include <linux/reboot.h> |
---|
19 | 17 | #include <linux/string.h> |
---|
20 | 18 | #include <linux/device.h> |
---|
.. | .. |
---|
32 | 30 | #include <linux/ctype.h> |
---|
33 | 31 | #include <linux/genhd.h> |
---|
34 | 32 | #include <linux/ktime.h> |
---|
| 33 | +#include <linux/security.h> |
---|
35 | 34 | #include <trace/events/power.h> |
---|
36 | 35 | |
---|
37 | 36 | #include "power.h" |
---|
.. | .. |
---|
68 | 67 | |
---|
69 | 68 | static const struct platform_hibernation_ops *hibernation_ops; |
---|
70 | 69 | |
---|
| 70 | +static atomic_t hibernate_atomic = ATOMIC_INIT(1); |
---|
| 71 | + |
---|
| 72 | +bool hibernate_acquire(void) |
---|
| 73 | +{ |
---|
| 74 | + return atomic_add_unless(&hibernate_atomic, -1, 0); |
---|
| 75 | +} |
---|
| 76 | + |
---|
| 77 | +void hibernate_release(void) |
---|
| 78 | +{ |
---|
| 79 | + atomic_inc(&hibernate_atomic); |
---|
| 80 | +} |
---|
| 81 | + |
---|
71 | 82 | bool hibernation_available(void) |
---|
72 | 83 | { |
---|
73 | | - return (nohibernate == 0); |
---|
| 84 | + return nohibernate == 0 && !security_locked_down(LOCKDOWN_HIBERNATION); |
---|
74 | 85 | } |
---|
75 | 86 | |
---|
76 | 87 | /** |
---|
.. | .. |
---|
107 | 118 | #ifdef CONFIG_PM_DEBUG |
---|
108 | 119 | static void hibernation_debug_sleep(void) |
---|
109 | 120 | { |
---|
110 | | - pr_info("hibernation debug: Waiting for 5 seconds.\n"); |
---|
| 121 | + pr_info("debug: Waiting for 5 seconds.\n"); |
---|
111 | 122 | mdelay(5000); |
---|
112 | 123 | } |
---|
113 | 124 | |
---|
.. | .. |
---|
130 | 141 | static int platform_begin(int platform_mode) |
---|
131 | 142 | { |
---|
132 | 143 | return (platform_mode && hibernation_ops) ? |
---|
133 | | - hibernation_ops->begin() : 0; |
---|
| 144 | + hibernation_ops->begin(PMSG_FREEZE) : 0; |
---|
134 | 145 | } |
---|
135 | 146 | |
---|
136 | 147 | /** |
---|
.. | .. |
---|
278 | 289 | |
---|
279 | 290 | error = dpm_suspend_end(PMSG_FREEZE); |
---|
280 | 291 | if (error) { |
---|
281 | | - pr_err("Some devices failed to power down, aborting hibernation\n"); |
---|
| 292 | + pr_err("Some devices failed to power down, aborting\n"); |
---|
282 | 293 | return error; |
---|
283 | 294 | } |
---|
284 | 295 | |
---|
.. | .. |
---|
286 | 297 | if (error || hibernation_test(TEST_PLATFORM)) |
---|
287 | 298 | goto Platform_finish; |
---|
288 | 299 | |
---|
289 | | - error = disable_nonboot_cpus(); |
---|
| 300 | + error = suspend_disable_secondary_cpus(); |
---|
290 | 301 | if (error || hibernation_test(TEST_CPUS)) |
---|
291 | 302 | goto Enable_cpus; |
---|
292 | 303 | |
---|
.. | .. |
---|
296 | 307 | |
---|
297 | 308 | error = syscore_suspend(); |
---|
298 | 309 | if (error) { |
---|
299 | | - pr_err("Some system devices failed to power down, aborting hibernation\n"); |
---|
| 310 | + pr_err("Some system devices failed to power down, aborting\n"); |
---|
300 | 311 | goto Enable_irqs; |
---|
301 | 312 | } |
---|
302 | 313 | |
---|
.. | .. |
---|
311 | 322 | restore_processor_state(); |
---|
312 | 323 | trace_suspend_resume(TPS("machine_suspend"), PM_EVENT_HIBERNATE, false); |
---|
313 | 324 | if (error) |
---|
314 | | - pr_err("Error %d creating hibernation image\n", error); |
---|
| 325 | + pr_err("Error %d creating image\n", error); |
---|
315 | 326 | |
---|
316 | 327 | if (!in_suspend) { |
---|
317 | 328 | events_check_enabled = false; |
---|
318 | | - clear_free_pages(); |
---|
| 329 | + clear_or_poison_free_pages(); |
---|
319 | 330 | } |
---|
320 | 331 | |
---|
321 | 332 | platform_leave(platform_mode); |
---|
.. | .. |
---|
328 | 339 | local_irq_enable(); |
---|
329 | 340 | |
---|
330 | 341 | Enable_cpus: |
---|
331 | | - enable_nonboot_cpus(); |
---|
| 342 | + suspend_enable_secondary_cpus(); |
---|
332 | 343 | |
---|
333 | 344 | /* Allow architectures to do nosmt-specific post-resume dances */ |
---|
334 | 345 | if (!in_suspend) |
---|
.. | .. |
---|
426 | 437 | |
---|
427 | 438 | int __weak hibernate_resume_nonboot_cpu_disable(void) |
---|
428 | 439 | { |
---|
429 | | - return disable_nonboot_cpus(); |
---|
| 440 | + return suspend_disable_secondary_cpus(); |
---|
430 | 441 | } |
---|
431 | 442 | |
---|
432 | 443 | /** |
---|
.. | .. |
---|
495 | 506 | local_irq_enable(); |
---|
496 | 507 | |
---|
497 | 508 | Enable_cpus: |
---|
498 | | - enable_nonboot_cpus(); |
---|
| 509 | + suspend_enable_secondary_cpus(); |
---|
499 | 510 | |
---|
500 | 511 | Cleanup: |
---|
501 | 512 | platform_restore_cleanup(platform_mode); |
---|
.. | .. |
---|
552 | 563 | * hibernation_ops->finish() before saving the image, so we should let |
---|
553 | 564 | * the firmware know that we're going to enter the sleep state after all |
---|
554 | 565 | */ |
---|
555 | | - error = hibernation_ops->begin(); |
---|
| 566 | + error = hibernation_ops->begin(PMSG_HIBERNATE); |
---|
556 | 567 | if (error) |
---|
557 | 568 | goto Close; |
---|
558 | 569 | |
---|
.. | .. |
---|
573 | 584 | if (error) |
---|
574 | 585 | goto Platform_finish; |
---|
575 | 586 | |
---|
576 | | - error = disable_nonboot_cpus(); |
---|
| 587 | + error = suspend_disable_secondary_cpus(); |
---|
577 | 588 | if (error) |
---|
578 | 589 | goto Enable_cpus; |
---|
579 | 590 | |
---|
.. | .. |
---|
595 | 606 | local_irq_enable(); |
---|
596 | 607 | |
---|
597 | 608 | Enable_cpus: |
---|
598 | | - enable_nonboot_cpus(); |
---|
| 609 | + suspend_enable_secondary_cpus(); |
---|
599 | 610 | |
---|
600 | 611 | Platform_finish: |
---|
601 | 612 | hibernation_ops->finish(); |
---|
.. | .. |
---|
626 | 637 | int error; |
---|
627 | 638 | |
---|
628 | 639 | if (hibernation_mode == HIBERNATION_SUSPEND) { |
---|
629 | | - error = suspend_devices_and_enter(PM_SUSPEND_MEM); |
---|
| 640 | + error = suspend_devices_and_enter(mem_sleep_current); |
---|
630 | 641 | if (error) { |
---|
631 | 642 | hibernation_mode = hibernation_ops ? |
---|
632 | 643 | HIBERNATION_PLATFORM : |
---|
.. | .. |
---|
648 | 659 | break; |
---|
649 | 660 | case HIBERNATION_PLATFORM: |
---|
650 | 661 | hibernation_platform_enter(); |
---|
651 | | - /* Fall through */ |
---|
| 662 | + fallthrough; |
---|
652 | 663 | case HIBERNATION_SHUTDOWN: |
---|
653 | 664 | if (pm_power_off) |
---|
654 | 665 | kernel_power_off(); |
---|
.. | .. |
---|
679 | 690 | error = swsusp_read(&flags); |
---|
680 | 691 | swsusp_close(FMODE_READ | FMODE_EXCL); |
---|
681 | 692 | if (!error) |
---|
682 | | - hibernation_restore(flags & SF_PLATFORM_MODE); |
---|
| 693 | + error = hibernation_restore(flags & SF_PLATFORM_MODE); |
---|
683 | 694 | |
---|
684 | | - pr_err("Failed to load hibernation image, recovering.\n"); |
---|
| 695 | + pr_err("Failed to load image, recovering.\n"); |
---|
685 | 696 | swsusp_free(); |
---|
686 | 697 | free_basic_memory_bitmaps(); |
---|
687 | 698 | Unlock: |
---|
.. | .. |
---|
690 | 701 | return error; |
---|
691 | 702 | } |
---|
692 | 703 | |
---|
693 | | -#ifndef CONFIG_SUSPEND |
---|
694 | | -bool pm_in_action; |
---|
695 | | -#endif |
---|
696 | | - |
---|
697 | 704 | /** |
---|
698 | 705 | * hibernate - Carry out system hibernation, including saving the image. |
---|
699 | 706 | */ |
---|
700 | 707 | int hibernate(void) |
---|
701 | 708 | { |
---|
702 | | - int error, nr_calls = 0; |
---|
703 | 709 | bool snapshot_test = false; |
---|
| 710 | + int error; |
---|
704 | 711 | |
---|
705 | 712 | if (!hibernation_available()) { |
---|
706 | 713 | pm_pr_dbg("Hibernation not available.\n"); |
---|
707 | 714 | return -EPERM; |
---|
708 | 715 | } |
---|
709 | 716 | |
---|
710 | | - pm_in_action = true; |
---|
711 | | - |
---|
712 | 717 | lock_system_sleep(); |
---|
713 | 718 | /* The snapshot device should not be opened while we're running */ |
---|
714 | | - if (!atomic_add_unless(&snapshot_device_available, -1, 0)) { |
---|
| 719 | + if (!hibernate_acquire()) { |
---|
715 | 720 | error = -EBUSY; |
---|
716 | 721 | goto Unlock; |
---|
717 | 722 | } |
---|
718 | 723 | |
---|
719 | 724 | pr_info("hibernation entry\n"); |
---|
720 | 725 | pm_prepare_console(); |
---|
721 | | - error = __pm_notifier_call_chain(PM_HIBERNATION_PREPARE, -1, &nr_calls); |
---|
722 | | - if (error) { |
---|
723 | | - nr_calls--; |
---|
724 | | - goto Exit; |
---|
725 | | - } |
---|
| 726 | + error = pm_notifier_call_chain_robust(PM_HIBERNATION_PREPARE, PM_POST_HIBERNATION); |
---|
| 727 | + if (error) |
---|
| 728 | + goto Restore; |
---|
726 | 729 | |
---|
727 | | - pr_info("Syncing filesystems ... \n"); |
---|
728 | | - ksys_sync(); |
---|
729 | | - pr_info("done.\n"); |
---|
| 730 | + ksys_sync_helper(); |
---|
730 | 731 | |
---|
731 | 732 | error = freeze_processes(); |
---|
732 | 733 | if (error) |
---|
.. | .. |
---|
752 | 753 | else |
---|
753 | 754 | flags |= SF_CRC32_MODE; |
---|
754 | 755 | |
---|
755 | | - pm_pr_dbg("Writing image.\n"); |
---|
| 756 | + pm_pr_dbg("Writing hibernation image.\n"); |
---|
756 | 757 | error = swsusp_write(flags); |
---|
757 | 758 | swsusp_free(); |
---|
758 | 759 | if (!error) { |
---|
.. | .. |
---|
764 | 765 | in_suspend = 0; |
---|
765 | 766 | pm_restore_gfp_mask(); |
---|
766 | 767 | } else { |
---|
767 | | - pm_pr_dbg("Image restored successfully.\n"); |
---|
| 768 | + pm_pr_dbg("Hibernation image restored successfully.\n"); |
---|
768 | 769 | } |
---|
769 | 770 | |
---|
770 | 771 | Free_bitmaps: |
---|
.. | .. |
---|
782 | 783 | /* Don't bother checking whether freezer_test_done is true */ |
---|
783 | 784 | freezer_test_done = false; |
---|
784 | 785 | Exit: |
---|
785 | | - __pm_notifier_call_chain(PM_POST_HIBERNATION, nr_calls, NULL); |
---|
| 786 | + pm_notifier_call_chain(PM_POST_HIBERNATION); |
---|
| 787 | + Restore: |
---|
786 | 788 | pm_restore_console(); |
---|
787 | | - atomic_inc(&snapshot_device_available); |
---|
| 789 | + hibernate_release(); |
---|
788 | 790 | Unlock: |
---|
789 | 791 | unlock_system_sleep(); |
---|
790 | | - pm_in_action = false; |
---|
791 | 792 | pr_info("hibernation exit\n"); |
---|
792 | 793 | |
---|
793 | 794 | return error; |
---|
794 | 795 | } |
---|
795 | 796 | |
---|
| 797 | +/** |
---|
| 798 | + * hibernate_quiet_exec - Execute a function with all devices frozen. |
---|
| 799 | + * @func: Function to execute. |
---|
| 800 | + * @data: Data pointer to pass to @func. |
---|
| 801 | + * |
---|
| 802 | + * Return the @func return value or an error code if it cannot be executed. |
---|
| 803 | + */ |
---|
| 804 | +int hibernate_quiet_exec(int (*func)(void *data), void *data) |
---|
| 805 | +{ |
---|
| 806 | + int error; |
---|
| 807 | + |
---|
| 808 | + lock_system_sleep(); |
---|
| 809 | + |
---|
| 810 | + if (!hibernate_acquire()) { |
---|
| 811 | + error = -EBUSY; |
---|
| 812 | + goto unlock; |
---|
| 813 | + } |
---|
| 814 | + |
---|
| 815 | + pm_prepare_console(); |
---|
| 816 | + |
---|
| 817 | + error = pm_notifier_call_chain_robust(PM_HIBERNATION_PREPARE, PM_POST_HIBERNATION); |
---|
| 818 | + if (error) |
---|
| 819 | + goto restore; |
---|
| 820 | + |
---|
| 821 | + error = freeze_processes(); |
---|
| 822 | + if (error) |
---|
| 823 | + goto exit; |
---|
| 824 | + |
---|
| 825 | + lock_device_hotplug(); |
---|
| 826 | + |
---|
| 827 | + pm_suspend_clear_flags(); |
---|
| 828 | + |
---|
| 829 | + error = platform_begin(true); |
---|
| 830 | + if (error) |
---|
| 831 | + goto thaw; |
---|
| 832 | + |
---|
| 833 | + error = freeze_kernel_threads(); |
---|
| 834 | + if (error) |
---|
| 835 | + goto thaw; |
---|
| 836 | + |
---|
| 837 | + error = dpm_prepare(PMSG_FREEZE); |
---|
| 838 | + if (error) |
---|
| 839 | + goto dpm_complete; |
---|
| 840 | + |
---|
| 841 | + suspend_console(); |
---|
| 842 | + |
---|
| 843 | + error = dpm_suspend(PMSG_FREEZE); |
---|
| 844 | + if (error) |
---|
| 845 | + goto dpm_resume; |
---|
| 846 | + |
---|
| 847 | + error = dpm_suspend_end(PMSG_FREEZE); |
---|
| 848 | + if (error) |
---|
| 849 | + goto dpm_resume; |
---|
| 850 | + |
---|
| 851 | + error = platform_pre_snapshot(true); |
---|
| 852 | + if (error) |
---|
| 853 | + goto skip; |
---|
| 854 | + |
---|
| 855 | + error = func(data); |
---|
| 856 | + |
---|
| 857 | +skip: |
---|
| 858 | + platform_finish(true); |
---|
| 859 | + |
---|
| 860 | + dpm_resume_start(PMSG_THAW); |
---|
| 861 | + |
---|
| 862 | +dpm_resume: |
---|
| 863 | + dpm_resume(PMSG_THAW); |
---|
| 864 | + |
---|
| 865 | + resume_console(); |
---|
| 866 | + |
---|
| 867 | +dpm_complete: |
---|
| 868 | + dpm_complete(PMSG_THAW); |
---|
| 869 | + |
---|
| 870 | + thaw_kernel_threads(); |
---|
| 871 | + |
---|
| 872 | +thaw: |
---|
| 873 | + platform_end(true); |
---|
| 874 | + |
---|
| 875 | + unlock_device_hotplug(); |
---|
| 876 | + |
---|
| 877 | + thaw_processes(); |
---|
| 878 | + |
---|
| 879 | +exit: |
---|
| 880 | + pm_notifier_call_chain(PM_POST_HIBERNATION); |
---|
| 881 | + |
---|
| 882 | +restore: |
---|
| 883 | + pm_restore_console(); |
---|
| 884 | + |
---|
| 885 | + hibernate_release(); |
---|
| 886 | + |
---|
| 887 | +unlock: |
---|
| 888 | + unlock_system_sleep(); |
---|
| 889 | + |
---|
| 890 | + return error; |
---|
| 891 | +} |
---|
| 892 | +EXPORT_SYMBOL_GPL(hibernate_quiet_exec); |
---|
796 | 893 | |
---|
797 | 894 | /** |
---|
798 | 895 | * software_resume - Resume from a saved hibernation image. |
---|
.. | .. |
---|
811 | 908 | */ |
---|
812 | 909 | static int software_resume(void) |
---|
813 | 910 | { |
---|
814 | | - int error, nr_calls = 0; |
---|
| 911 | + int error; |
---|
815 | 912 | |
---|
816 | 913 | /* |
---|
817 | 914 | * If the user said "noresume".. bail out early. |
---|
.. | .. |
---|
879 | 976 | goto Unlock; |
---|
880 | 977 | |
---|
881 | 978 | /* The snapshot device should not be opened while we're running */ |
---|
882 | | - if (!atomic_add_unless(&snapshot_device_available, -1, 0)) { |
---|
| 979 | + if (!hibernate_acquire()) { |
---|
883 | 980 | error = -EBUSY; |
---|
884 | 981 | swsusp_close(FMODE_READ | FMODE_EXCL); |
---|
885 | 982 | goto Unlock; |
---|
.. | .. |
---|
887 | 984 | |
---|
888 | 985 | pr_info("resume from hibernation\n"); |
---|
889 | 986 | pm_prepare_console(); |
---|
890 | | - error = __pm_notifier_call_chain(PM_RESTORE_PREPARE, -1, &nr_calls); |
---|
891 | | - if (error) { |
---|
892 | | - nr_calls--; |
---|
893 | | - goto Close_Finish; |
---|
894 | | - } |
---|
| 987 | + error = pm_notifier_call_chain_robust(PM_RESTORE_PREPARE, PM_POST_RESTORE); |
---|
| 988 | + if (error) |
---|
| 989 | + goto Restore; |
---|
895 | 990 | |
---|
896 | | - pm_pr_dbg("Preparing processes for restore.\n"); |
---|
| 991 | + pm_pr_dbg("Preparing processes for hibernation restore.\n"); |
---|
897 | 992 | error = freeze_processes(); |
---|
898 | 993 | if (error) |
---|
899 | 994 | goto Close_Finish; |
---|
.. | .. |
---|
907 | 1002 | error = load_image_and_restore(); |
---|
908 | 1003 | thaw_processes(); |
---|
909 | 1004 | Finish: |
---|
910 | | - __pm_notifier_call_chain(PM_POST_RESTORE, nr_calls, NULL); |
---|
| 1005 | + pm_notifier_call_chain(PM_POST_RESTORE); |
---|
| 1006 | + Restore: |
---|
911 | 1007 | pm_restore_console(); |
---|
912 | | - pr_info("resume from hibernation failed (%d)\n", error); |
---|
913 | | - atomic_inc(&snapshot_device_available); |
---|
| 1008 | + pr_info("resume failed (%d)\n", error); |
---|
| 1009 | + hibernate_release(); |
---|
914 | 1010 | /* For success case, the suspend path will release the lock */ |
---|
915 | 1011 | Unlock: |
---|
916 | 1012 | mutex_unlock(&system_transition_mutex); |
---|
.. | .. |
---|
1049 | 1145 | static ssize_t resume_show(struct kobject *kobj, struct kobj_attribute *attr, |
---|
1050 | 1146 | char *buf) |
---|
1051 | 1147 | { |
---|
1052 | | - return sprintf(buf,"%d:%d\n", MAJOR(swsusp_resume_device), |
---|
| 1148 | + return sprintf(buf, "%d:%d\n", MAJOR(swsusp_resume_device), |
---|
1053 | 1149 | MINOR(swsusp_resume_device)); |
---|
1054 | 1150 | } |
---|
1055 | 1151 | |
---|
.. | .. |
---|
1074 | 1170 | lock_system_sleep(); |
---|
1075 | 1171 | swsusp_resume_device = res; |
---|
1076 | 1172 | unlock_system_sleep(); |
---|
1077 | | - pm_pr_dbg("Configured resume from disk to %u\n", swsusp_resume_device); |
---|
| 1173 | + pm_pr_dbg("Configured hibernation resume from disk to %u\n", |
---|
| 1174 | + swsusp_resume_device); |
---|
1078 | 1175 | noresume = 0; |
---|
1079 | 1176 | software_resume(); |
---|
1080 | 1177 | return n; |
---|
.. | .. |
---|
1148 | 1245 | |
---|
1149 | 1246 | power_attr(reserved_size); |
---|
1150 | 1247 | |
---|
1151 | | -static struct attribute * g[] = { |
---|
| 1248 | +static struct attribute *g[] = { |
---|
1152 | 1249 | &disk_attr.attr, |
---|
1153 | 1250 | &resume_offset_attr.attr, |
---|
1154 | 1251 | &resume_attr.attr, |
---|
.. | .. |
---|
1176 | 1273 | if (noresume) |
---|
1177 | 1274 | return 1; |
---|
1178 | 1275 | |
---|
1179 | | - strncpy( resume_file, str, 255 ); |
---|
| 1276 | + strncpy(resume_file, str, 255); |
---|
1180 | 1277 | return 1; |
---|
1181 | 1278 | } |
---|
1182 | 1279 | |
---|
.. | .. |
---|
1226 | 1323 | int rc = kstrtouint(str, 0, &resume_delay); |
---|
1227 | 1324 | |
---|
1228 | 1325 | if (rc) |
---|
1229 | | - return rc; |
---|
| 1326 | + pr_warn("resumedelay: bad option string '%s'\n", str); |
---|
1230 | 1327 | return 1; |
---|
1231 | 1328 | } |
---|
1232 | 1329 | |
---|