aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/power
diff options
context:
space:
mode:
authorLianwei Wang <lianwei.wang@gmail.com>2016-06-20 02:52:27 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2016-06-27 18:38:55 -0400
commitea00f4f4f00cc2bc3b63ad512a4e6df3b20832b9 (patch)
tree148dbab1f94bc7dd515c6ddda12f85bae310dd4f /kernel/power
parentca5f2b4c4fb7bb7397317ee2ead83485aa295a3e (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.c20
-rw-r--r--kernel/power/main.c11
-rw-r--r--kernel/power/power.h2
-rw-r--r--kernel/power/suspend.c10
-rw-r--r--kernel/power/user.c14
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 */
648int hibernate(void) 648int 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 */
741static int software_resume(void) 743static 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}
39EXPORT_SYMBOL_GPL(unregister_pm_notifier); 39EXPORT_SYMBOL_GPL(unregister_pm_notifier);
40 40
41int pm_notifier_call_chain(unsigned long val) 41int __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}
50int 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. */
49int pm_async_enabled = 1; 56int 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 */
203extern int __pm_notifier_call_chain(unsigned long val, int nr_to_call,
204 int *nr_calls);
203extern int pm_notifier_call_chain(unsigned long val); 205extern 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 */
267static int suspend_prepare(suspend_state_t state) 267static 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);
47static int snapshot_open(struct inode *inode, struct file *filp) 47static 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);