diff options
| author | Lianwei Wang <lianwei.wang@gmail.com> | 2016-06-20 02:52:27 -0400 |
|---|---|---|
| committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2016-06-27 18:38:55 -0400 |
| commit | ea00f4f4f00cc2bc3b63ad512a4e6df3b20832b9 (patch) | |
| tree | 148dbab1f94bc7dd515c6ddda12f85bae310dd4f /kernel/power | |
| parent | ca5f2b4c4fb7bb7397317ee2ead83485aa295a3e (diff) | |
PM / sleep: make PM notifiers called symmetrically
This makes pm notifier PREPARE/POST symmetrical: if PREPARE
fails, we will only undo what ever happened on PREPARE.
It fixes the unbalanced CPU hotplug enable in CPU PM notifier.
Signed-off-by: Lianwei Wang <lianwei.wang@gmail.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'kernel/power')
| -rw-r--r-- | kernel/power/hibernate.c | 20 | ||||
| -rw-r--r-- | kernel/power/main.c | 11 | ||||
| -rw-r--r-- | kernel/power/power.h | 2 | ||||
| -rw-r--r-- | kernel/power/suspend.c | 10 | ||||
| -rw-r--r-- | kernel/power/user.c | 14 |
5 files changed, 37 insertions, 20 deletions
diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c index fca9254280ee..126e24caa82e 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c | |||
| @@ -647,7 +647,7 @@ static void power_down(void) | |||
| 647 | */ | 647 | */ |
| 648 | int hibernate(void) | 648 | int hibernate(void) |
| 649 | { | 649 | { |
| 650 | int error; | 650 | int error, nr_calls = 0; |
| 651 | 651 | ||
| 652 | if (!hibernation_available()) { | 652 | if (!hibernation_available()) { |
| 653 | pr_debug("PM: Hibernation not available.\n"); | 653 | pr_debug("PM: Hibernation not available.\n"); |
| @@ -662,9 +662,11 @@ int hibernate(void) | |||
| 662 | } | 662 | } |
| 663 | 663 | ||
| 664 | pm_prepare_console(); | 664 | pm_prepare_console(); |
| 665 | error = pm_notifier_call_chain(PM_HIBERNATION_PREPARE); | 665 | error = __pm_notifier_call_chain(PM_HIBERNATION_PREPARE, -1, &nr_calls); |
| 666 | if (error) | 666 | if (error) { |
| 667 | nr_calls--; | ||
| 667 | goto Exit; | 668 | goto Exit; |
| 669 | } | ||
| 668 | 670 | ||
| 669 | printk(KERN_INFO "PM: Syncing filesystems ... "); | 671 | printk(KERN_INFO "PM: Syncing filesystems ... "); |
| 670 | sys_sync(); | 672 | sys_sync(); |
| @@ -714,7 +716,7 @@ int hibernate(void) | |||
| 714 | /* Don't bother checking whether freezer_test_done is true */ | 716 | /* Don't bother checking whether freezer_test_done is true */ |
| 715 | freezer_test_done = false; | 717 | freezer_test_done = false; |
| 716 | Exit: | 718 | Exit: |
| 717 | pm_notifier_call_chain(PM_POST_HIBERNATION); | 719 | __pm_notifier_call_chain(PM_POST_HIBERNATION, nr_calls, NULL); |
| 718 | pm_restore_console(); | 720 | pm_restore_console(); |
| 719 | atomic_inc(&snapshot_device_available); | 721 | atomic_inc(&snapshot_device_available); |
| 720 | Unlock: | 722 | Unlock: |
| @@ -740,7 +742,7 @@ int hibernate(void) | |||
| 740 | */ | 742 | */ |
| 741 | static int software_resume(void) | 743 | static int software_resume(void) |
| 742 | { | 744 | { |
| 743 | int error; | 745 | int error, nr_calls = 0; |
| 744 | unsigned int flags; | 746 | unsigned int flags; |
| 745 | 747 | ||
| 746 | /* | 748 | /* |
| @@ -827,9 +829,11 @@ static int software_resume(void) | |||
| 827 | } | 829 | } |
| 828 | 830 | ||
| 829 | pm_prepare_console(); | 831 | pm_prepare_console(); |
| 830 | error = pm_notifier_call_chain(PM_RESTORE_PREPARE); | 832 | error = __pm_notifier_call_chain(PM_RESTORE_PREPARE, -1, &nr_calls); |
| 831 | if (error) | 833 | if (error) { |
| 834 | nr_calls--; | ||
| 832 | goto Close_Finish; | 835 | goto Close_Finish; |
| 836 | } | ||
| 833 | 837 | ||
| 834 | pr_debug("PM: Preparing processes for restore.\n"); | 838 | pr_debug("PM: Preparing processes for restore.\n"); |
| 835 | error = freeze_processes(); | 839 | error = freeze_processes(); |
| @@ -855,7 +859,7 @@ static int software_resume(void) | |||
| 855 | unlock_device_hotplug(); | 859 | unlock_device_hotplug(); |
| 856 | thaw_processes(); | 860 | thaw_processes(); |
| 857 | Finish: | 861 | Finish: |
| 858 | pm_notifier_call_chain(PM_POST_RESTORE); | 862 | __pm_notifier_call_chain(PM_POST_RESTORE, nr_calls, NULL); |
| 859 | pm_restore_console(); | 863 | pm_restore_console(); |
| 860 | atomic_inc(&snapshot_device_available); | 864 | atomic_inc(&snapshot_device_available); |
| 861 | /* For success case, the suspend path will release the lock */ | 865 | /* For success case, the suspend path will release the lock */ |
diff --git a/kernel/power/main.c b/kernel/power/main.c index 27946975eff0..5ea50b1b7595 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c | |||
| @@ -38,12 +38,19 @@ int unregister_pm_notifier(struct notifier_block *nb) | |||
| 38 | } | 38 | } |
| 39 | EXPORT_SYMBOL_GPL(unregister_pm_notifier); | 39 | EXPORT_SYMBOL_GPL(unregister_pm_notifier); |
| 40 | 40 | ||
| 41 | int pm_notifier_call_chain(unsigned long val) | 41 | int __pm_notifier_call_chain(unsigned long val, int nr_to_call, int *nr_calls) |
| 42 | { | 42 | { |
| 43 | int ret = blocking_notifier_call_chain(&pm_chain_head, val, NULL); | 43 | int ret; |
| 44 | |||
| 45 | ret = __blocking_notifier_call_chain(&pm_chain_head, val, NULL, | ||
| 46 | nr_to_call, nr_calls); | ||
| 44 | 47 | ||
| 45 | return notifier_to_errno(ret); | 48 | return notifier_to_errno(ret); |
| 46 | } | 49 | } |
| 50 | int pm_notifier_call_chain(unsigned long val) | ||
| 51 | { | ||
| 52 | return __pm_notifier_call_chain(val, -1, NULL); | ||
| 53 | } | ||
| 47 | 54 | ||
| 48 | /* If set, devices may be suspended and resumed asynchronously. */ | 55 | /* If set, devices may be suspended and resumed asynchronously. */ |
| 49 | int pm_async_enabled = 1; | 56 | int pm_async_enabled = 1; |
diff --git a/kernel/power/power.h b/kernel/power/power.h index efe1b3b17c88..51f02ecaf125 100644 --- a/kernel/power/power.h +++ b/kernel/power/power.h | |||
| @@ -200,6 +200,8 @@ static inline void suspend_test_finish(const char *label) {} | |||
| 200 | 200 | ||
| 201 | #ifdef CONFIG_PM_SLEEP | 201 | #ifdef CONFIG_PM_SLEEP |
| 202 | /* kernel/power/main.c */ | 202 | /* kernel/power/main.c */ |
| 203 | extern int __pm_notifier_call_chain(unsigned long val, int nr_to_call, | ||
| 204 | int *nr_calls); | ||
| 203 | extern int pm_notifier_call_chain(unsigned long val); | 205 | extern int pm_notifier_call_chain(unsigned long val); |
| 204 | #endif | 206 | #endif |
| 205 | 207 | ||
diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index 5b70d64b871e..0acab9d7f96f 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c | |||
| @@ -266,16 +266,18 @@ static int suspend_test(int level) | |||
| 266 | */ | 266 | */ |
| 267 | static int suspend_prepare(suspend_state_t state) | 267 | static int suspend_prepare(suspend_state_t state) |
| 268 | { | 268 | { |
| 269 | int error; | 269 | int error, nr_calls = 0; |
| 270 | 270 | ||
| 271 | if (!sleep_state_supported(state)) | 271 | if (!sleep_state_supported(state)) |
| 272 | return -EPERM; | 272 | return -EPERM; |
| 273 | 273 | ||
| 274 | pm_prepare_console(); | 274 | pm_prepare_console(); |
| 275 | 275 | ||
| 276 | error = pm_notifier_call_chain(PM_SUSPEND_PREPARE); | 276 | error = __pm_notifier_call_chain(PM_SUSPEND_PREPARE, -1, &nr_calls); |
| 277 | if (error) | 277 | if (error) { |
| 278 | nr_calls--; | ||
| 278 | goto Finish; | 279 | goto Finish; |
| 280 | } | ||
| 279 | 281 | ||
| 280 | trace_suspend_resume(TPS("freeze_processes"), 0, true); | 282 | trace_suspend_resume(TPS("freeze_processes"), 0, true); |
| 281 | error = suspend_freeze_processes(); | 283 | error = suspend_freeze_processes(); |
| @@ -286,7 +288,7 @@ static int suspend_prepare(suspend_state_t state) | |||
| 286 | suspend_stats.failed_freeze++; | 288 | suspend_stats.failed_freeze++; |
| 287 | dpm_save_failed_step(SUSPEND_FREEZE); | 289 | dpm_save_failed_step(SUSPEND_FREEZE); |
| 288 | Finish: | 290 | Finish: |
| 289 | pm_notifier_call_chain(PM_POST_SUSPEND); | 291 | __pm_notifier_call_chain(PM_POST_SUSPEND, nr_calls, NULL); |
| 290 | pm_restore_console(); | 292 | pm_restore_console(); |
| 291 | return error; | 293 | return error; |
| 292 | } | 294 | } |
diff --git a/kernel/power/user.c b/kernel/power/user.c index 526e8911460a..35310b627388 100644 --- a/kernel/power/user.c +++ b/kernel/power/user.c | |||
| @@ -47,7 +47,7 @@ atomic_t snapshot_device_available = ATOMIC_INIT(1); | |||
| 47 | static int snapshot_open(struct inode *inode, struct file *filp) | 47 | static int snapshot_open(struct inode *inode, struct file *filp) |
| 48 | { | 48 | { |
| 49 | struct snapshot_data *data; | 49 | struct snapshot_data *data; |
| 50 | int error; | 50 | int error, nr_calls = 0; |
| 51 | 51 | ||
| 52 | if (!hibernation_available()) | 52 | if (!hibernation_available()) |
| 53 | return -EPERM; | 53 | return -EPERM; |
| @@ -74,9 +74,9 @@ static int snapshot_open(struct inode *inode, struct file *filp) | |||
| 74 | swap_type_of(swsusp_resume_device, 0, NULL) : -1; | 74 | swap_type_of(swsusp_resume_device, 0, NULL) : -1; |
| 75 | data->mode = O_RDONLY; | 75 | data->mode = O_RDONLY; |
| 76 | data->free_bitmaps = false; | 76 | data->free_bitmaps = false; |
| 77 | error = pm_notifier_call_chain(PM_HIBERNATION_PREPARE); | 77 | error = __pm_notifier_call_chain(PM_HIBERNATION_PREPARE, -1, &nr_calls); |
| 78 | if (error) | 78 | if (error) |
| 79 | pm_notifier_call_chain(PM_POST_HIBERNATION); | 79 | __pm_notifier_call_chain(PM_POST_HIBERNATION, --nr_calls, NULL); |
| 80 | } else { | 80 | } else { |
| 81 | /* | 81 | /* |
| 82 | * Resuming. We may need to wait for the image device to | 82 | * Resuming. We may need to wait for the image device to |
| @@ -86,13 +86,15 @@ static int snapshot_open(struct inode *inode, struct file *filp) | |||
| 86 | 86 | ||
| 87 | data->swap = -1; | 87 | data->swap = -1; |
| 88 | data->mode = O_WRONLY; | 88 | data->mode = O_WRONLY; |
| 89 | error = pm_notifier_call_chain(PM_RESTORE_PREPARE); | 89 | error = __pm_notifier_call_chain(PM_RESTORE_PREPARE, -1, &nr_calls); |
| 90 | if (!error) { | 90 | if (!error) { |
| 91 | error = create_basic_memory_bitmaps(); | 91 | error = create_basic_memory_bitmaps(); |
| 92 | data->free_bitmaps = !error; | 92 | data->free_bitmaps = !error; |
| 93 | } | 93 | } else |
| 94 | nr_calls--; | ||
| 95 | |||
| 94 | if (error) | 96 | if (error) |
| 95 | pm_notifier_call_chain(PM_POST_RESTORE); | 97 | __pm_notifier_call_chain(PM_POST_RESTORE, nr_calls, NULL); |
| 96 | } | 98 | } |
| 97 | if (error) | 99 | if (error) |
| 98 | atomic_inc(&snapshot_device_available); | 100 | atomic_inc(&snapshot_device_available); |
