diff options
author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2012-03-09 13:55:17 -0500 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2012-03-09 13:55:17 -0500 |
commit | b675b3667f6729dcd1036a2a129b35445947f905 (patch) | |
tree | 0d58791e9063d3ca2c352da6f3e7df2bdb876f9d /kernel/power | |
parent | 104a5f3cad8f2f27cadbdf0029400ecd9e17ccc0 (diff) | |
parent | 192cfd58774b4d17b2fe8bdc77d89c2ef4e0591d (diff) |
Merge commit 'v3.3-rc6' into next
Diffstat (limited to 'kernel/power')
-rw-r--r-- | kernel/power/hibernate.c | 104 | ||||
-rw-r--r-- | kernel/power/main.c | 10 | ||||
-rw-r--r-- | kernel/power/power.h | 26 | ||||
-rw-r--r-- | kernel/power/process.c | 93 | ||||
-rw-r--r-- | kernel/power/snapshot.c | 9 | ||||
-rw-r--r-- | kernel/power/suspend.c | 12 | ||||
-rw-r--r-- | kernel/power/swap.c | 14 | ||||
-rw-r--r-- | kernel/power/user.c | 195 |
8 files changed, 227 insertions, 236 deletions
diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c index 196c01268ebd..6d6d28870335 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c | |||
@@ -43,8 +43,6 @@ int in_suspend __nosavedata; | |||
43 | enum { | 43 | enum { |
44 | HIBERNATION_INVALID, | 44 | HIBERNATION_INVALID, |
45 | HIBERNATION_PLATFORM, | 45 | HIBERNATION_PLATFORM, |
46 | HIBERNATION_TEST, | ||
47 | HIBERNATION_TESTPROC, | ||
48 | HIBERNATION_SHUTDOWN, | 46 | HIBERNATION_SHUTDOWN, |
49 | HIBERNATION_REBOOT, | 47 | HIBERNATION_REBOOT, |
50 | /* keep last */ | 48 | /* keep last */ |
@@ -55,7 +53,7 @@ enum { | |||
55 | 53 | ||
56 | static int hibernation_mode = HIBERNATION_SHUTDOWN; | 54 | static int hibernation_mode = HIBERNATION_SHUTDOWN; |
57 | 55 | ||
58 | static bool freezer_test_done; | 56 | bool freezer_test_done; |
59 | 57 | ||
60 | static const struct platform_hibernation_ops *hibernation_ops; | 58 | static const struct platform_hibernation_ops *hibernation_ops; |
61 | 59 | ||
@@ -71,14 +69,14 @@ void hibernation_set_ops(const struct platform_hibernation_ops *ops) | |||
71 | WARN_ON(1); | 69 | WARN_ON(1); |
72 | return; | 70 | return; |
73 | } | 71 | } |
74 | mutex_lock(&pm_mutex); | 72 | lock_system_sleep(); |
75 | hibernation_ops = ops; | 73 | hibernation_ops = ops; |
76 | if (ops) | 74 | if (ops) |
77 | hibernation_mode = HIBERNATION_PLATFORM; | 75 | hibernation_mode = HIBERNATION_PLATFORM; |
78 | else if (hibernation_mode == HIBERNATION_PLATFORM) | 76 | else if (hibernation_mode == HIBERNATION_PLATFORM) |
79 | hibernation_mode = HIBERNATION_SHUTDOWN; | 77 | hibernation_mode = HIBERNATION_SHUTDOWN; |
80 | 78 | ||
81 | mutex_unlock(&pm_mutex); | 79 | unlock_system_sleep(); |
82 | } | 80 | } |
83 | 81 | ||
84 | static bool entering_platform_hibernation; | 82 | static bool entering_platform_hibernation; |
@@ -96,15 +94,6 @@ static void hibernation_debug_sleep(void) | |||
96 | mdelay(5000); | 94 | mdelay(5000); |
97 | } | 95 | } |
98 | 96 | ||
99 | static int hibernation_testmode(int mode) | ||
100 | { | ||
101 | if (hibernation_mode == mode) { | ||
102 | hibernation_debug_sleep(); | ||
103 | return 1; | ||
104 | } | ||
105 | return 0; | ||
106 | } | ||
107 | |||
108 | static int hibernation_test(int level) | 97 | static int hibernation_test(int level) |
109 | { | 98 | { |
110 | if (pm_test_level == level) { | 99 | if (pm_test_level == level) { |
@@ -114,7 +103,6 @@ static int hibernation_test(int level) | |||
114 | return 0; | 103 | return 0; |
115 | } | 104 | } |
116 | #else /* !CONFIG_PM_DEBUG */ | 105 | #else /* !CONFIG_PM_DEBUG */ |
117 | static int hibernation_testmode(int mode) { return 0; } | ||
118 | static int hibernation_test(int level) { return 0; } | 106 | static int hibernation_test(int level) { return 0; } |
119 | #endif /* !CONFIG_PM_DEBUG */ | 107 | #endif /* !CONFIG_PM_DEBUG */ |
120 | 108 | ||
@@ -278,8 +266,7 @@ static int create_image(int platform_mode) | |||
278 | goto Platform_finish; | 266 | goto Platform_finish; |
279 | 267 | ||
280 | error = disable_nonboot_cpus(); | 268 | error = disable_nonboot_cpus(); |
281 | if (error || hibernation_test(TEST_CPUS) | 269 | if (error || hibernation_test(TEST_CPUS)) |
282 | || hibernation_testmode(HIBERNATION_TEST)) | ||
283 | goto Enable_cpus; | 270 | goto Enable_cpus; |
284 | 271 | ||
285 | local_irq_disable(); | 272 | local_irq_disable(); |
@@ -333,7 +320,7 @@ static int create_image(int platform_mode) | |||
333 | */ | 320 | */ |
334 | int hibernation_snapshot(int platform_mode) | 321 | int hibernation_snapshot(int platform_mode) |
335 | { | 322 | { |
336 | pm_message_t msg = PMSG_RECOVER; | 323 | pm_message_t msg; |
337 | int error; | 324 | int error; |
338 | 325 | ||
339 | error = platform_begin(platform_mode); | 326 | error = platform_begin(platform_mode); |
@@ -347,39 +334,40 @@ int hibernation_snapshot(int platform_mode) | |||
347 | 334 | ||
348 | error = freeze_kernel_threads(); | 335 | error = freeze_kernel_threads(); |
349 | if (error) | 336 | if (error) |
350 | goto Close; | 337 | goto Cleanup; |
351 | 338 | ||
352 | if (hibernation_test(TEST_FREEZER) || | 339 | if (hibernation_test(TEST_FREEZER)) { |
353 | hibernation_testmode(HIBERNATION_TESTPROC)) { | ||
354 | 340 | ||
355 | /* | 341 | /* |
356 | * Indicate to the caller that we are returning due to a | 342 | * Indicate to the caller that we are returning due to a |
357 | * successful freezer test. | 343 | * successful freezer test. |
358 | */ | 344 | */ |
359 | freezer_test_done = true; | 345 | freezer_test_done = true; |
360 | goto Close; | 346 | goto Cleanup; |
361 | } | 347 | } |
362 | 348 | ||
363 | error = dpm_prepare(PMSG_FREEZE); | 349 | error = dpm_prepare(PMSG_FREEZE); |
364 | if (error) | 350 | if (error) { |
365 | goto Complete_devices; | 351 | dpm_complete(PMSG_RECOVER); |
352 | goto Cleanup; | ||
353 | } | ||
366 | 354 | ||
367 | suspend_console(); | 355 | suspend_console(); |
368 | pm_restrict_gfp_mask(); | 356 | pm_restrict_gfp_mask(); |
357 | |||
369 | error = dpm_suspend(PMSG_FREEZE); | 358 | error = dpm_suspend(PMSG_FREEZE); |
370 | if (error) | ||
371 | goto Recover_platform; | ||
372 | 359 | ||
373 | if (hibernation_test(TEST_DEVICES)) | 360 | if (error || hibernation_test(TEST_DEVICES)) |
374 | goto Recover_platform; | 361 | platform_recover(platform_mode); |
362 | else | ||
363 | error = create_image(platform_mode); | ||
375 | 364 | ||
376 | error = create_image(platform_mode); | ||
377 | /* | 365 | /* |
378 | * Control returns here (1) after the image has been created or the | 366 | * In the case that we call create_image() above, the control |
367 | * returns here (1) after the image has been created or the | ||
379 | * image creation has failed and (2) after a successful restore. | 368 | * image creation has failed and (2) after a successful restore. |
380 | */ | 369 | */ |
381 | 370 | ||
382 | Resume_devices: | ||
383 | /* We may need to release the preallocated image pages here. */ | 371 | /* We may need to release the preallocated image pages here. */ |
384 | if (error || !in_suspend) | 372 | if (error || !in_suspend) |
385 | swsusp_free(); | 373 | swsusp_free(); |
@@ -391,17 +379,15 @@ int hibernation_snapshot(int platform_mode) | |||
391 | pm_restore_gfp_mask(); | 379 | pm_restore_gfp_mask(); |
392 | 380 | ||
393 | resume_console(); | 381 | resume_console(); |
394 | |||
395 | Complete_devices: | ||
396 | dpm_complete(msg); | 382 | dpm_complete(msg); |
397 | 383 | ||
398 | Close: | 384 | Close: |
399 | platform_end(platform_mode); | 385 | platform_end(platform_mode); |
400 | return error; | 386 | return error; |
401 | 387 | ||
402 | Recover_platform: | 388 | Cleanup: |
403 | platform_recover(platform_mode); | 389 | swsusp_free(); |
404 | goto Resume_devices; | 390 | goto Close; |
405 | } | 391 | } |
406 | 392 | ||
407 | /** | 393 | /** |
@@ -586,9 +572,6 @@ int hibernation_platform_enter(void) | |||
586 | static void power_down(void) | 572 | static void power_down(void) |
587 | { | 573 | { |
588 | switch (hibernation_mode) { | 574 | switch (hibernation_mode) { |
589 | case HIBERNATION_TEST: | ||
590 | case HIBERNATION_TESTPROC: | ||
591 | break; | ||
592 | case HIBERNATION_REBOOT: | 575 | case HIBERNATION_REBOOT: |
593 | kernel_restart(NULL); | 576 | kernel_restart(NULL); |
594 | break; | 577 | break; |
@@ -607,17 +590,6 @@ static void power_down(void) | |||
607 | while(1); | 590 | while(1); |
608 | } | 591 | } |
609 | 592 | ||
610 | static int prepare_processes(void) | ||
611 | { | ||
612 | int error = 0; | ||
613 | |||
614 | if (freeze_processes()) { | ||
615 | error = -EBUSY; | ||
616 | thaw_processes(); | ||
617 | } | ||
618 | return error; | ||
619 | } | ||
620 | |||
621 | /** | 593 | /** |
622 | * hibernate - Carry out system hibernation, including saving the image. | 594 | * hibernate - Carry out system hibernation, including saving the image. |
623 | */ | 595 | */ |
@@ -625,7 +597,7 @@ int hibernate(void) | |||
625 | { | 597 | { |
626 | int error; | 598 | int error; |
627 | 599 | ||
628 | mutex_lock(&pm_mutex); | 600 | lock_system_sleep(); |
629 | /* The snapshot device should not be opened while we're running */ | 601 | /* The snapshot device should not be opened while we're running */ |
630 | if (!atomic_add_unless(&snapshot_device_available, -1, 0)) { | 602 | if (!atomic_add_unless(&snapshot_device_available, -1, 0)) { |
631 | error = -EBUSY; | 603 | error = -EBUSY; |
@@ -650,7 +622,7 @@ int hibernate(void) | |||
650 | sys_sync(); | 622 | sys_sync(); |
651 | printk("done.\n"); | 623 | printk("done.\n"); |
652 | 624 | ||
653 | error = prepare_processes(); | 625 | error = freeze_processes(); |
654 | if (error) | 626 | if (error) |
655 | goto Finish; | 627 | goto Finish; |
656 | 628 | ||
@@ -693,7 +665,7 @@ int hibernate(void) | |||
693 | pm_restore_console(); | 665 | pm_restore_console(); |
694 | atomic_inc(&snapshot_device_available); | 666 | atomic_inc(&snapshot_device_available); |
695 | Unlock: | 667 | Unlock: |
696 | mutex_unlock(&pm_mutex); | 668 | unlock_system_sleep(); |
697 | return error; | 669 | return error; |
698 | } | 670 | } |
699 | 671 | ||
@@ -807,11 +779,13 @@ static int software_resume(void) | |||
807 | goto close_finish; | 779 | goto close_finish; |
808 | 780 | ||
809 | error = create_basic_memory_bitmaps(); | 781 | error = create_basic_memory_bitmaps(); |
810 | if (error) | 782 | if (error) { |
783 | usermodehelper_enable(); | ||
811 | goto close_finish; | 784 | goto close_finish; |
785 | } | ||
812 | 786 | ||
813 | pr_debug("PM: Preparing processes for restore.\n"); | 787 | pr_debug("PM: Preparing processes for restore.\n"); |
814 | error = prepare_processes(); | 788 | error = freeze_processes(); |
815 | if (error) { | 789 | if (error) { |
816 | swsusp_close(FMODE_READ); | 790 | swsusp_close(FMODE_READ); |
817 | goto Done; | 791 | goto Done; |
@@ -851,8 +825,6 @@ static const char * const hibernation_modes[] = { | |||
851 | [HIBERNATION_PLATFORM] = "platform", | 825 | [HIBERNATION_PLATFORM] = "platform", |
852 | [HIBERNATION_SHUTDOWN] = "shutdown", | 826 | [HIBERNATION_SHUTDOWN] = "shutdown", |
853 | [HIBERNATION_REBOOT] = "reboot", | 827 | [HIBERNATION_REBOOT] = "reboot", |
854 | [HIBERNATION_TEST] = "test", | ||
855 | [HIBERNATION_TESTPROC] = "testproc", | ||
856 | }; | 828 | }; |
857 | 829 | ||
858 | /* | 830 | /* |
@@ -861,17 +833,15 @@ static const char * const hibernation_modes[] = { | |||
861 | * Hibernation can be handled in several ways. There are a few different ways | 833 | * Hibernation can be handled in several ways. There are a few different ways |
862 | * to put the system into the sleep state: using the platform driver (e.g. ACPI | 834 | * to put the system into the sleep state: using the platform driver (e.g. ACPI |
863 | * or other hibernation_ops), powering it off or rebooting it (for testing | 835 | * or other hibernation_ops), powering it off or rebooting it (for testing |
864 | * mostly), or using one of the two available test modes. | 836 | * mostly). |
865 | * | 837 | * |
866 | * The sysfs file /sys/power/disk provides an interface for selecting the | 838 | * The sysfs file /sys/power/disk provides an interface for selecting the |
867 | * hibernation mode to use. Reading from this file causes the available modes | 839 | * hibernation mode to use. Reading from this file causes the available modes |
868 | * to be printed. There are 5 modes that can be supported: | 840 | * to be printed. There are 3 modes that can be supported: |
869 | * | 841 | * |
870 | * 'platform' | 842 | * 'platform' |
871 | * 'shutdown' | 843 | * 'shutdown' |
872 | * 'reboot' | 844 | * 'reboot' |
873 | * 'test' | ||
874 | * 'testproc' | ||
875 | * | 845 | * |
876 | * If a platform hibernation driver is in use, 'platform' will be supported | 846 | * If a platform hibernation driver is in use, 'platform' will be supported |
877 | * and will be used by default. Otherwise, 'shutdown' will be used by default. | 847 | * and will be used by default. Otherwise, 'shutdown' will be used by default. |
@@ -895,8 +865,6 @@ static ssize_t disk_show(struct kobject *kobj, struct kobj_attribute *attr, | |||
895 | switch (i) { | 865 | switch (i) { |
896 | case HIBERNATION_SHUTDOWN: | 866 | case HIBERNATION_SHUTDOWN: |
897 | case HIBERNATION_REBOOT: | 867 | case HIBERNATION_REBOOT: |
898 | case HIBERNATION_TEST: | ||
899 | case HIBERNATION_TESTPROC: | ||
900 | break; | 868 | break; |
901 | case HIBERNATION_PLATFORM: | 869 | case HIBERNATION_PLATFORM: |
902 | if (hibernation_ops) | 870 | if (hibernation_ops) |
@@ -925,7 +893,7 @@ static ssize_t disk_store(struct kobject *kobj, struct kobj_attribute *attr, | |||
925 | p = memchr(buf, '\n', n); | 893 | p = memchr(buf, '\n', n); |
926 | len = p ? p - buf : n; | 894 | len = p ? p - buf : n; |
927 | 895 | ||
928 | mutex_lock(&pm_mutex); | 896 | lock_system_sleep(); |
929 | for (i = HIBERNATION_FIRST; i <= HIBERNATION_MAX; i++) { | 897 | for (i = HIBERNATION_FIRST; i <= HIBERNATION_MAX; i++) { |
930 | if (len == strlen(hibernation_modes[i]) | 898 | if (len == strlen(hibernation_modes[i]) |
931 | && !strncmp(buf, hibernation_modes[i], len)) { | 899 | && !strncmp(buf, hibernation_modes[i], len)) { |
@@ -937,8 +905,6 @@ static ssize_t disk_store(struct kobject *kobj, struct kobj_attribute *attr, | |||
937 | switch (mode) { | 905 | switch (mode) { |
938 | case HIBERNATION_SHUTDOWN: | 906 | case HIBERNATION_SHUTDOWN: |
939 | case HIBERNATION_REBOOT: | 907 | case HIBERNATION_REBOOT: |
940 | case HIBERNATION_TEST: | ||
941 | case HIBERNATION_TESTPROC: | ||
942 | hibernation_mode = mode; | 908 | hibernation_mode = mode; |
943 | break; | 909 | break; |
944 | case HIBERNATION_PLATFORM: | 910 | case HIBERNATION_PLATFORM: |
@@ -953,7 +919,7 @@ static ssize_t disk_store(struct kobject *kobj, struct kobj_attribute *attr, | |||
953 | if (!error) | 919 | if (!error) |
954 | pr_debug("PM: Hibernation mode set to '%s'\n", | 920 | pr_debug("PM: Hibernation mode set to '%s'\n", |
955 | hibernation_modes[mode]); | 921 | hibernation_modes[mode]); |
956 | mutex_unlock(&pm_mutex); | 922 | unlock_system_sleep(); |
957 | return error ? error : n; | 923 | return error ? error : n; |
958 | } | 924 | } |
959 | 925 | ||
@@ -980,9 +946,9 @@ static ssize_t resume_store(struct kobject *kobj, struct kobj_attribute *attr, | |||
980 | if (maj != MAJOR(res) || min != MINOR(res)) | 946 | if (maj != MAJOR(res) || min != MINOR(res)) |
981 | goto out; | 947 | goto out; |
982 | 948 | ||
983 | mutex_lock(&pm_mutex); | 949 | lock_system_sleep(); |
984 | swsusp_resume_device = res; | 950 | swsusp_resume_device = res; |
985 | mutex_unlock(&pm_mutex); | 951 | unlock_system_sleep(); |
986 | printk(KERN_INFO "PM: Starting manual resume from disk\n"); | 952 | printk(KERN_INFO "PM: Starting manual resume from disk\n"); |
987 | noresume = 0; | 953 | noresume = 0; |
988 | software_resume(); | 954 | software_resume(); |
diff --git a/kernel/power/main.c b/kernel/power/main.c index 36e0f0903c32..9824b41e5a18 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * Copyright (c) 2003 Patrick Mochel | 4 | * Copyright (c) 2003 Patrick Mochel |
5 | * Copyright (c) 2003 Open Source Development Lab | 5 | * Copyright (c) 2003 Open Source Development Lab |
6 | * | 6 | * |
7 | * This file is released under the GPLv2 | 7 | * This file is released under the GPLv2 |
8 | * | 8 | * |
9 | */ | 9 | */ |
@@ -116,7 +116,7 @@ static ssize_t pm_test_store(struct kobject *kobj, struct kobj_attribute *attr, | |||
116 | p = memchr(buf, '\n', n); | 116 | p = memchr(buf, '\n', n); |
117 | len = p ? p - buf : n; | 117 | len = p ? p - buf : n; |
118 | 118 | ||
119 | mutex_lock(&pm_mutex); | 119 | lock_system_sleep(); |
120 | 120 | ||
121 | level = TEST_FIRST; | 121 | level = TEST_FIRST; |
122 | for (s = &pm_tests[level]; level <= TEST_MAX; s++, level++) | 122 | for (s = &pm_tests[level]; level <= TEST_MAX; s++, level++) |
@@ -126,7 +126,7 @@ static ssize_t pm_test_store(struct kobject *kobj, struct kobj_attribute *attr, | |||
126 | break; | 126 | break; |
127 | } | 127 | } |
128 | 128 | ||
129 | mutex_unlock(&pm_mutex); | 129 | unlock_system_sleep(); |
130 | 130 | ||
131 | return error ? error : n; | 131 | return error ? error : n; |
132 | } | 132 | } |
@@ -240,7 +240,7 @@ struct kobject *power_kobj; | |||
240 | * 'standby' (Power-On Suspend), 'mem' (Suspend-to-RAM), and | 240 | * 'standby' (Power-On Suspend), 'mem' (Suspend-to-RAM), and |
241 | * 'disk' (Suspend-to-Disk). | 241 | * 'disk' (Suspend-to-Disk). |
242 | * | 242 | * |
243 | * store() accepts one of those strings, translates it into the | 243 | * store() accepts one of those strings, translates it into the |
244 | * proper enumerated value, and initiates a suspend transition. | 244 | * proper enumerated value, and initiates a suspend transition. |
245 | */ | 245 | */ |
246 | static ssize_t state_show(struct kobject *kobj, struct kobj_attribute *attr, | 246 | static ssize_t state_show(struct kobject *kobj, struct kobj_attribute *attr, |
@@ -282,7 +282,7 @@ static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr, | |||
282 | /* First, check if we are requested to hibernate */ | 282 | /* First, check if we are requested to hibernate */ |
283 | if (len == 4 && !strncmp(buf, "disk", len)) { | 283 | if (len == 4 && !strncmp(buf, "disk", len)) { |
284 | error = hibernate(); | 284 | error = hibernate(); |
285 | goto Exit; | 285 | goto Exit; |
286 | } | 286 | } |
287 | 287 | ||
288 | #ifdef CONFIG_SUSPEND | 288 | #ifdef CONFIG_SUSPEND |
diff --git a/kernel/power/power.h b/kernel/power/power.h index 23a2db1ec442..21724eee5206 100644 --- a/kernel/power/power.h +++ b/kernel/power/power.h | |||
@@ -50,6 +50,8 @@ static inline char *check_image_kernel(struct swsusp_info *info) | |||
50 | #define SPARE_PAGES ((1024 * 1024) >> PAGE_SHIFT) | 50 | #define SPARE_PAGES ((1024 * 1024) >> PAGE_SHIFT) |
51 | 51 | ||
52 | /* kernel/power/hibernate.c */ | 52 | /* kernel/power/hibernate.c */ |
53 | extern bool freezer_test_done; | ||
54 | |||
53 | extern int hibernation_snapshot(int platform_mode); | 55 | extern int hibernation_snapshot(int platform_mode); |
54 | extern int hibernation_restore(int platform_mode); | 56 | extern int hibernation_restore(int platform_mode); |
55 | extern int hibernation_platform_enter(void); | 57 | extern int hibernation_platform_enter(void); |
@@ -229,8 +231,28 @@ extern int pm_test_level; | |||
229 | #ifdef CONFIG_SUSPEND_FREEZER | 231 | #ifdef CONFIG_SUSPEND_FREEZER |
230 | static inline int suspend_freeze_processes(void) | 232 | static inline int suspend_freeze_processes(void) |
231 | { | 233 | { |
232 | int error = freeze_processes(); | 234 | int error; |
233 | return error ? : freeze_kernel_threads(); | 235 | |
236 | error = freeze_processes(); | ||
237 | |||
238 | /* | ||
239 | * freeze_processes() automatically thaws every task if freezing | ||
240 | * fails. So we need not do anything extra upon error. | ||
241 | */ | ||
242 | if (error) | ||
243 | goto Finish; | ||
244 | |||
245 | error = freeze_kernel_threads(); | ||
246 | |||
247 | /* | ||
248 | * freeze_kernel_threads() thaws only kernel threads upon freezing | ||
249 | * failure. So we have to thaw the userspace tasks ourselves. | ||
250 | */ | ||
251 | if (error) | ||
252 | thaw_processes(); | ||
253 | |||
254 | Finish: | ||
255 | return error; | ||
234 | } | 256 | } |
235 | 257 | ||
236 | static inline void suspend_thaw_processes(void) | 258 | static inline void suspend_thaw_processes(void) |
diff --git a/kernel/power/process.c b/kernel/power/process.c index addbbe5531bc..7e426459e60a 100644 --- a/kernel/power/process.c +++ b/kernel/power/process.c | |||
@@ -22,16 +22,7 @@ | |||
22 | */ | 22 | */ |
23 | #define TIMEOUT (20 * HZ) | 23 | #define TIMEOUT (20 * HZ) |
24 | 24 | ||
25 | static inline int freezable(struct task_struct * p) | 25 | static int try_to_freeze_tasks(bool user_only) |
26 | { | ||
27 | if ((p == current) || | ||
28 | (p->flags & PF_NOFREEZE) || | ||
29 | (p->exit_state != 0)) | ||
30 | return 0; | ||
31 | return 1; | ||
32 | } | ||
33 | |||
34 | static int try_to_freeze_tasks(bool sig_only) | ||
35 | { | 26 | { |
36 | struct task_struct *g, *p; | 27 | struct task_struct *g, *p; |
37 | unsigned long end_time; | 28 | unsigned long end_time; |
@@ -46,17 +37,14 @@ static int try_to_freeze_tasks(bool sig_only) | |||
46 | 37 | ||
47 | end_time = jiffies + TIMEOUT; | 38 | end_time = jiffies + TIMEOUT; |
48 | 39 | ||
49 | if (!sig_only) | 40 | if (!user_only) |
50 | freeze_workqueues_begin(); | 41 | freeze_workqueues_begin(); |
51 | 42 | ||
52 | while (true) { | 43 | while (true) { |
53 | todo = 0; | 44 | todo = 0; |
54 | read_lock(&tasklist_lock); | 45 | read_lock(&tasklist_lock); |
55 | do_each_thread(g, p) { | 46 | do_each_thread(g, p) { |
56 | if (frozen(p) || !freezable(p)) | 47 | if (p == current || !freeze_task(p)) |
57 | continue; | ||
58 | |||
59 | if (!freeze_task(p, sig_only)) | ||
60 | continue; | 48 | continue; |
61 | 49 | ||
62 | /* | 50 | /* |
@@ -77,7 +65,7 @@ static int try_to_freeze_tasks(bool sig_only) | |||
77 | } while_each_thread(g, p); | 65 | } while_each_thread(g, p); |
78 | read_unlock(&tasklist_lock); | 66 | read_unlock(&tasklist_lock); |
79 | 67 | ||
80 | if (!sig_only) { | 68 | if (!user_only) { |
81 | wq_busy = freeze_workqueues_busy(); | 69 | wq_busy = freeze_workqueues_busy(); |
82 | todo += wq_busy; | 70 | todo += wq_busy; |
83 | } | 71 | } |
@@ -103,11 +91,6 @@ static int try_to_freeze_tasks(bool sig_only) | |||
103 | elapsed_csecs = elapsed_csecs64; | 91 | elapsed_csecs = elapsed_csecs64; |
104 | 92 | ||
105 | if (todo) { | 93 | if (todo) { |
106 | /* This does not unfreeze processes that are already frozen | ||
107 | * (we have slightly ugly calling convention in that respect, | ||
108 | * and caller must call thaw_processes() if something fails), | ||
109 | * but it cleans up leftover PF_FREEZE requests. | ||
110 | */ | ||
111 | printk("\n"); | 94 | printk("\n"); |
112 | printk(KERN_ERR "Freezing of tasks %s after %d.%02d seconds " | 95 | printk(KERN_ERR "Freezing of tasks %s after %d.%02d seconds " |
113 | "(%d tasks refusing to freeze, wq_busy=%d):\n", | 96 | "(%d tasks refusing to freeze, wq_busy=%d):\n", |
@@ -115,15 +98,11 @@ static int try_to_freeze_tasks(bool sig_only) | |||
115 | elapsed_csecs / 100, elapsed_csecs % 100, | 98 | elapsed_csecs / 100, elapsed_csecs % 100, |
116 | todo - wq_busy, wq_busy); | 99 | todo - wq_busy, wq_busy); |
117 | 100 | ||
118 | thaw_workqueues(); | ||
119 | |||
120 | read_lock(&tasklist_lock); | 101 | read_lock(&tasklist_lock); |
121 | do_each_thread(g, p) { | 102 | do_each_thread(g, p) { |
122 | task_lock(p); | 103 | if (!wakeup && !freezer_should_skip(p) && |
123 | if (!wakeup && freezing(p) && !freezer_should_skip(p)) | 104 | p != current && freezing(p) && !frozen(p)) |
124 | sched_show_task(p); | 105 | sched_show_task(p); |
125 | cancel_freezing(p); | ||
126 | task_unlock(p); | ||
127 | } while_each_thread(g, p); | 106 | } while_each_thread(g, p); |
128 | read_unlock(&tasklist_lock); | 107 | read_unlock(&tasklist_lock); |
129 | } else { | 108 | } else { |
@@ -136,12 +115,18 @@ static int try_to_freeze_tasks(bool sig_only) | |||
136 | 115 | ||
137 | /** | 116 | /** |
138 | * freeze_processes - Signal user space processes to enter the refrigerator. | 117 | * freeze_processes - Signal user space processes to enter the refrigerator. |
118 | * | ||
119 | * On success, returns 0. On failure, -errno and system is fully thawed. | ||
139 | */ | 120 | */ |
140 | int freeze_processes(void) | 121 | int freeze_processes(void) |
141 | { | 122 | { |
142 | int error; | 123 | int error; |
143 | 124 | ||
125 | if (!pm_freezing) | ||
126 | atomic_inc(&system_freezing_cnt); | ||
127 | |||
144 | printk("Freezing user space processes ... "); | 128 | printk("Freezing user space processes ... "); |
129 | pm_freezing = true; | ||
145 | error = try_to_freeze_tasks(true); | 130 | error = try_to_freeze_tasks(true); |
146 | if (!error) { | 131 | if (!error) { |
147 | printk("done."); | 132 | printk("done."); |
@@ -150,17 +135,25 @@ int freeze_processes(void) | |||
150 | printk("\n"); | 135 | printk("\n"); |
151 | BUG_ON(in_atomic()); | 136 | BUG_ON(in_atomic()); |
152 | 137 | ||
138 | if (error) | ||
139 | thaw_processes(); | ||
153 | return error; | 140 | return error; |
154 | } | 141 | } |
155 | 142 | ||
156 | /** | 143 | /** |
157 | * freeze_kernel_threads - Make freezable kernel threads go to the refrigerator. | 144 | * freeze_kernel_threads - Make freezable kernel threads go to the refrigerator. |
145 | * | ||
146 | * On success, returns 0. On failure, -errno and only the kernel threads are | ||
147 | * thawed, so as to give a chance to the caller to do additional cleanups | ||
148 | * (if any) before thawing the userspace tasks. So, it is the responsibility | ||
149 | * of the caller to thaw the userspace tasks, when the time is right. | ||
158 | */ | 150 | */ |
159 | int freeze_kernel_threads(void) | 151 | int freeze_kernel_threads(void) |
160 | { | 152 | { |
161 | int error; | 153 | int error; |
162 | 154 | ||
163 | printk("Freezing remaining freezable tasks ... "); | 155 | printk("Freezing remaining freezable tasks ... "); |
156 | pm_nosig_freezing = true; | ||
164 | error = try_to_freeze_tasks(false); | 157 | error = try_to_freeze_tasks(false); |
165 | if (!error) | 158 | if (!error) |
166 | printk("done."); | 159 | printk("done."); |
@@ -168,38 +161,52 @@ int freeze_kernel_threads(void) | |||
168 | printk("\n"); | 161 | printk("\n"); |
169 | BUG_ON(in_atomic()); | 162 | BUG_ON(in_atomic()); |
170 | 163 | ||
164 | if (error) | ||
165 | thaw_kernel_threads(); | ||
171 | return error; | 166 | return error; |
172 | } | 167 | } |
173 | 168 | ||
174 | static void thaw_tasks(bool nosig_only) | 169 | void thaw_processes(void) |
175 | { | 170 | { |
176 | struct task_struct *g, *p; | 171 | struct task_struct *g, *p; |
177 | 172 | ||
178 | read_lock(&tasklist_lock); | 173 | if (pm_freezing) |
179 | do_each_thread(g, p) { | 174 | atomic_dec(&system_freezing_cnt); |
180 | if (!freezable(p)) | 175 | pm_freezing = false; |
181 | continue; | 176 | pm_nosig_freezing = false; |
182 | 177 | ||
183 | if (nosig_only && should_send_signal(p)) | 178 | oom_killer_enable(); |
184 | continue; | 179 | |
180 | printk("Restarting tasks ... "); | ||
185 | 181 | ||
186 | if (cgroup_freezing_or_frozen(p)) | 182 | thaw_workqueues(); |
187 | continue; | ||
188 | 183 | ||
189 | thaw_process(p); | 184 | read_lock(&tasklist_lock); |
185 | do_each_thread(g, p) { | ||
186 | __thaw_task(p); | ||
190 | } while_each_thread(g, p); | 187 | } while_each_thread(g, p); |
191 | read_unlock(&tasklist_lock); | 188 | read_unlock(&tasklist_lock); |
189 | |||
190 | schedule(); | ||
191 | printk("done.\n"); | ||
192 | } | 192 | } |
193 | 193 | ||
194 | void thaw_processes(void) | 194 | void thaw_kernel_threads(void) |
195 | { | 195 | { |
196 | oom_killer_enable(); | 196 | struct task_struct *g, *p; |
197 | |||
198 | pm_nosig_freezing = false; | ||
199 | printk("Restarting kernel threads ... "); | ||
197 | 200 | ||
198 | printk("Restarting tasks ... "); | ||
199 | thaw_workqueues(); | 201 | thaw_workqueues(); |
200 | thaw_tasks(true); | 202 | |
201 | thaw_tasks(false); | 203 | read_lock(&tasklist_lock); |
204 | do_each_thread(g, p) { | ||
205 | if (p->flags & (PF_KTHREAD | PF_WQ_WORKER)) | ||
206 | __thaw_task(p); | ||
207 | } while_each_thread(g, p); | ||
208 | read_unlock(&tasklist_lock); | ||
209 | |||
202 | schedule(); | 210 | schedule(); |
203 | printk("done.\n"); | 211 | printk("done.\n"); |
204 | } | 212 | } |
205 | |||
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c index cbe2c1441392..6a768e537001 100644 --- a/kernel/power/snapshot.c +++ b/kernel/power/snapshot.c | |||
@@ -812,7 +812,8 @@ unsigned int snapshot_additional_pages(struct zone *zone) | |||
812 | unsigned int res; | 812 | unsigned int res; |
813 | 813 | ||
814 | res = DIV_ROUND_UP(zone->spanned_pages, BM_BITS_PER_BLOCK); | 814 | res = DIV_ROUND_UP(zone->spanned_pages, BM_BITS_PER_BLOCK); |
815 | res += DIV_ROUND_UP(res * sizeof(struct bm_block), PAGE_SIZE); | 815 | res += DIV_ROUND_UP(res * sizeof(struct bm_block), |
816 | LINKED_PAGE_DATA_SIZE); | ||
816 | return 2 * res; | 817 | return 2 * res; |
817 | } | 818 | } |
818 | 819 | ||
@@ -858,6 +859,9 @@ static struct page *saveable_highmem_page(struct zone *zone, unsigned long pfn) | |||
858 | PageReserved(page)) | 859 | PageReserved(page)) |
859 | return NULL; | 860 | return NULL; |
860 | 861 | ||
862 | if (page_is_guard(page)) | ||
863 | return NULL; | ||
864 | |||
861 | return page; | 865 | return page; |
862 | } | 866 | } |
863 | 867 | ||
@@ -920,6 +924,9 @@ static struct page *saveable_page(struct zone *zone, unsigned long pfn) | |||
920 | && (!kernel_page_present(page) || pfn_is_nosave(pfn))) | 924 | && (!kernel_page_present(page) || pfn_is_nosave(pfn))) |
921 | return NULL; | 925 | return NULL; |
922 | 926 | ||
927 | if (page_is_guard(page)) | ||
928 | return NULL; | ||
929 | |||
923 | return page; | 930 | return page; |
924 | } | 931 | } |
925 | 932 | ||
diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index 4953dc054c53..4fd51beed879 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c | |||
@@ -42,9 +42,9 @@ static const struct platform_suspend_ops *suspend_ops; | |||
42 | */ | 42 | */ |
43 | void suspend_set_ops(const struct platform_suspend_ops *ops) | 43 | void suspend_set_ops(const struct platform_suspend_ops *ops) |
44 | { | 44 | { |
45 | mutex_lock(&pm_mutex); | 45 | lock_system_sleep(); |
46 | suspend_ops = ops; | 46 | suspend_ops = ops; |
47 | mutex_unlock(&pm_mutex); | 47 | unlock_system_sleep(); |
48 | } | 48 | } |
49 | EXPORT_SYMBOL_GPL(suspend_set_ops); | 49 | EXPORT_SYMBOL_GPL(suspend_set_ops); |
50 | 50 | ||
@@ -106,13 +106,11 @@ static int suspend_prepare(void) | |||
106 | goto Finish; | 106 | goto Finish; |
107 | 107 | ||
108 | error = suspend_freeze_processes(); | 108 | error = suspend_freeze_processes(); |
109 | if (error) { | 109 | if (!error) |
110 | suspend_stats.failed_freeze++; | ||
111 | dpm_save_failed_step(SUSPEND_FREEZE); | ||
112 | } else | ||
113 | return 0; | 110 | return 0; |
114 | 111 | ||
115 | suspend_thaw_processes(); | 112 | suspend_stats.failed_freeze++; |
113 | dpm_save_failed_step(SUSPEND_FREEZE); | ||
116 | usermodehelper_enable(); | 114 | usermodehelper_enable(); |
117 | Finish: | 115 | Finish: |
118 | pm_notifier_call_chain(PM_POST_SUSPEND); | 116 | pm_notifier_call_chain(PM_POST_SUSPEND); |
diff --git a/kernel/power/swap.c b/kernel/power/swap.c index 11a594c4ba25..8742fd013a94 100644 --- a/kernel/power/swap.c +++ b/kernel/power/swap.c | |||
@@ -18,7 +18,6 @@ | |||
18 | #include <linux/bitops.h> | 18 | #include <linux/bitops.h> |
19 | #include <linux/genhd.h> | 19 | #include <linux/genhd.h> |
20 | #include <linux/device.h> | 20 | #include <linux/device.h> |
21 | #include <linux/buffer_head.h> | ||
22 | #include <linux/bio.h> | 21 | #include <linux/bio.h> |
23 | #include <linux/blkdev.h> | 22 | #include <linux/blkdev.h> |
24 | #include <linux/swap.h> | 23 | #include <linux/swap.h> |
@@ -774,8 +773,7 @@ static int enough_swap(unsigned int nr_pages, unsigned int flags) | |||
774 | 773 | ||
775 | pr_debug("PM: Free swap pages: %u\n", free_swap); | 774 | pr_debug("PM: Free swap pages: %u\n", free_swap); |
776 | 775 | ||
777 | required = PAGES_FOR_IO + ((flags & SF_NOCOMPRESS_MODE) ? | 776 | required = PAGES_FOR_IO + nr_pages; |
778 | nr_pages : (nr_pages * LZO_CMP_PAGES) / LZO_UNC_PAGES + 1); | ||
779 | return free_swap > required; | 777 | return free_swap > required; |
780 | } | 778 | } |
781 | 779 | ||
@@ -803,10 +801,12 @@ int swsusp_write(unsigned int flags) | |||
803 | printk(KERN_ERR "PM: Cannot get swap writer\n"); | 801 | printk(KERN_ERR "PM: Cannot get swap writer\n"); |
804 | return error; | 802 | return error; |
805 | } | 803 | } |
806 | if (!enough_swap(pages, flags)) { | 804 | if (flags & SF_NOCOMPRESS_MODE) { |
807 | printk(KERN_ERR "PM: Not enough free swap\n"); | 805 | if (!enough_swap(pages, flags)) { |
808 | error = -ENOSPC; | 806 | printk(KERN_ERR "PM: Not enough free swap\n"); |
809 | goto out_finish; | 807 | error = -ENOSPC; |
808 | goto out_finish; | ||
809 | } | ||
810 | } | 810 | } |
811 | memset(&snapshot, 0, sizeof(struct snapshot_handle)); | 811 | memset(&snapshot, 0, sizeof(struct snapshot_handle)); |
812 | error = snapshot_read_next(&snapshot); | 812 | error = snapshot_read_next(&snapshot); |
diff --git a/kernel/power/user.c b/kernel/power/user.c index 6d8f535c2b88..3e100075b13c 100644 --- a/kernel/power/user.c +++ b/kernel/power/user.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/swapops.h> | 21 | #include <linux/swapops.h> |
22 | #include <linux/pm.h> | 22 | #include <linux/pm.h> |
23 | #include <linux/fs.h> | 23 | #include <linux/fs.h> |
24 | #include <linux/compat.h> | ||
24 | #include <linux/console.h> | 25 | #include <linux/console.h> |
25 | #include <linux/cpu.h> | 26 | #include <linux/cpu.h> |
26 | #include <linux/freezer.h> | 27 | #include <linux/freezer.h> |
@@ -30,28 +31,6 @@ | |||
30 | 31 | ||
31 | #include "power.h" | 32 | #include "power.h" |
32 | 33 | ||
33 | /* | ||
34 | * NOTE: The SNAPSHOT_SET_SWAP_FILE and SNAPSHOT_PMOPS ioctls are obsolete and | ||
35 | * will be removed in the future. They are only preserved here for | ||
36 | * compatibility with existing userland utilities. | ||
37 | */ | ||
38 | #define SNAPSHOT_SET_SWAP_FILE _IOW(SNAPSHOT_IOC_MAGIC, 10, unsigned int) | ||
39 | #define SNAPSHOT_PMOPS _IOW(SNAPSHOT_IOC_MAGIC, 12, unsigned int) | ||
40 | |||
41 | #define PMOPS_PREPARE 1 | ||
42 | #define PMOPS_ENTER 2 | ||
43 | #define PMOPS_FINISH 3 | ||
44 | |||
45 | /* | ||
46 | * NOTE: The following ioctl definitions are wrong and have been replaced with | ||
47 | * correct ones. They are only preserved here for compatibility with existing | ||
48 | * userland utilities and will be removed in the future. | ||
49 | */ | ||
50 | #define SNAPSHOT_ATOMIC_SNAPSHOT _IOW(SNAPSHOT_IOC_MAGIC, 3, void *) | ||
51 | #define SNAPSHOT_SET_IMAGE_SIZE _IOW(SNAPSHOT_IOC_MAGIC, 6, unsigned long) | ||
52 | #define SNAPSHOT_AVAIL_SWAP _IOR(SNAPSHOT_IOC_MAGIC, 7, void *) | ||
53 | #define SNAPSHOT_GET_SWAP_PAGE _IOR(SNAPSHOT_IOC_MAGIC, 8, void *) | ||
54 | |||
55 | 34 | ||
56 | #define SNAPSHOT_MINOR 231 | 35 | #define SNAPSHOT_MINOR 231 |
57 | 36 | ||
@@ -71,7 +50,7 @@ static int snapshot_open(struct inode *inode, struct file *filp) | |||
71 | struct snapshot_data *data; | 50 | struct snapshot_data *data; |
72 | int error; | 51 | int error; |
73 | 52 | ||
74 | mutex_lock(&pm_mutex); | 53 | lock_system_sleep(); |
75 | 54 | ||
76 | if (!atomic_add_unless(&snapshot_device_available, -1, 0)) { | 55 | if (!atomic_add_unless(&snapshot_device_available, -1, 0)) { |
77 | error = -EBUSY; | 56 | error = -EBUSY; |
@@ -123,7 +102,7 @@ static int snapshot_open(struct inode *inode, struct file *filp) | |||
123 | data->platform_support = 0; | 102 | data->platform_support = 0; |
124 | 103 | ||
125 | Unlock: | 104 | Unlock: |
126 | mutex_unlock(&pm_mutex); | 105 | unlock_system_sleep(); |
127 | 106 | ||
128 | return error; | 107 | return error; |
129 | } | 108 | } |
@@ -132,7 +111,7 @@ static int snapshot_release(struct inode *inode, struct file *filp) | |||
132 | { | 111 | { |
133 | struct snapshot_data *data; | 112 | struct snapshot_data *data; |
134 | 113 | ||
135 | mutex_lock(&pm_mutex); | 114 | lock_system_sleep(); |
136 | 115 | ||
137 | swsusp_free(); | 116 | swsusp_free(); |
138 | free_basic_memory_bitmaps(); | 117 | free_basic_memory_bitmaps(); |
@@ -146,7 +125,7 @@ static int snapshot_release(struct inode *inode, struct file *filp) | |||
146 | PM_POST_HIBERNATION : PM_POST_RESTORE); | 125 | PM_POST_HIBERNATION : PM_POST_RESTORE); |
147 | atomic_inc(&snapshot_device_available); | 126 | atomic_inc(&snapshot_device_available); |
148 | 127 | ||
149 | mutex_unlock(&pm_mutex); | 128 | unlock_system_sleep(); |
150 | 129 | ||
151 | return 0; | 130 | return 0; |
152 | } | 131 | } |
@@ -158,7 +137,7 @@ static ssize_t snapshot_read(struct file *filp, char __user *buf, | |||
158 | ssize_t res; | 137 | ssize_t res; |
159 | loff_t pg_offp = *offp & ~PAGE_MASK; | 138 | loff_t pg_offp = *offp & ~PAGE_MASK; |
160 | 139 | ||
161 | mutex_lock(&pm_mutex); | 140 | lock_system_sleep(); |
162 | 141 | ||
163 | data = filp->private_data; | 142 | data = filp->private_data; |
164 | if (!data->ready) { | 143 | if (!data->ready) { |
@@ -179,7 +158,7 @@ static ssize_t snapshot_read(struct file *filp, char __user *buf, | |||
179 | *offp += res; | 158 | *offp += res; |
180 | 159 | ||
181 | Unlock: | 160 | Unlock: |
182 | mutex_unlock(&pm_mutex); | 161 | unlock_system_sleep(); |
183 | 162 | ||
184 | return res; | 163 | return res; |
185 | } | 164 | } |
@@ -191,7 +170,7 @@ static ssize_t snapshot_write(struct file *filp, const char __user *buf, | |||
191 | ssize_t res; | 170 | ssize_t res; |
192 | loff_t pg_offp = *offp & ~PAGE_MASK; | 171 | loff_t pg_offp = *offp & ~PAGE_MASK; |
193 | 172 | ||
194 | mutex_lock(&pm_mutex); | 173 | lock_system_sleep(); |
195 | 174 | ||
196 | data = filp->private_data; | 175 | data = filp->private_data; |
197 | 176 | ||
@@ -208,20 +187,11 @@ static ssize_t snapshot_write(struct file *filp, const char __user *buf, | |||
208 | if (res > 0) | 187 | if (res > 0) |
209 | *offp += res; | 188 | *offp += res; |
210 | unlock: | 189 | unlock: |
211 | mutex_unlock(&pm_mutex); | 190 | unlock_system_sleep(); |
212 | 191 | ||
213 | return res; | 192 | return res; |
214 | } | 193 | } |
215 | 194 | ||
216 | static void snapshot_deprecated_ioctl(unsigned int cmd) | ||
217 | { | ||
218 | if (printk_ratelimit()) | ||
219 | printk(KERN_NOTICE "%pf: ioctl '%.8x' is deprecated and will " | ||
220 | "be removed soon, update your suspend-to-disk " | ||
221 | "utilities\n", | ||
222 | __builtin_return_address(0), cmd); | ||
223 | } | ||
224 | |||
225 | static long snapshot_ioctl(struct file *filp, unsigned int cmd, | 195 | static long snapshot_ioctl(struct file *filp, unsigned int cmd, |
226 | unsigned long arg) | 196 | unsigned long arg) |
227 | { | 197 | { |
@@ -257,11 +227,9 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd, | |||
257 | break; | 227 | break; |
258 | 228 | ||
259 | error = freeze_processes(); | 229 | error = freeze_processes(); |
260 | if (error) { | 230 | if (error) |
261 | thaw_processes(); | ||
262 | usermodehelper_enable(); | 231 | usermodehelper_enable(); |
263 | } | 232 | else |
264 | if (!error) | ||
265 | data->frozen = 1; | 233 | data->frozen = 1; |
266 | break; | 234 | break; |
267 | 235 | ||
@@ -274,8 +242,6 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd, | |||
274 | data->frozen = 0; | 242 | data->frozen = 0; |
275 | break; | 243 | break; |
276 | 244 | ||
277 | case SNAPSHOT_ATOMIC_SNAPSHOT: | ||
278 | snapshot_deprecated_ioctl(cmd); | ||
279 | case SNAPSHOT_CREATE_IMAGE: | 245 | case SNAPSHOT_CREATE_IMAGE: |
280 | if (data->mode != O_RDONLY || !data->frozen || data->ready) { | 246 | if (data->mode != O_RDONLY || !data->frozen || data->ready) { |
281 | error = -EPERM; | 247 | error = -EPERM; |
@@ -283,10 +249,17 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd, | |||
283 | } | 249 | } |
284 | pm_restore_gfp_mask(); | 250 | pm_restore_gfp_mask(); |
285 | error = hibernation_snapshot(data->platform_support); | 251 | error = hibernation_snapshot(data->platform_support); |
286 | if (!error) | 252 | if (error) { |
253 | thaw_kernel_threads(); | ||
254 | } else { | ||
287 | error = put_user(in_suspend, (int __user *)arg); | 255 | error = put_user(in_suspend, (int __user *)arg); |
288 | if (!error) | 256 | if (!error && !freezer_test_done) |
289 | data->ready = 1; | 257 | data->ready = 1; |
258 | if (freezer_test_done) { | ||
259 | freezer_test_done = false; | ||
260 | thaw_kernel_threads(); | ||
261 | } | ||
262 | } | ||
290 | break; | 263 | break; |
291 | 264 | ||
292 | case SNAPSHOT_ATOMIC_RESTORE: | 265 | case SNAPSHOT_ATOMIC_RESTORE: |
@@ -303,10 +276,17 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd, | |||
303 | swsusp_free(); | 276 | swsusp_free(); |
304 | memset(&data->handle, 0, sizeof(struct snapshot_handle)); | 277 | memset(&data->handle, 0, sizeof(struct snapshot_handle)); |
305 | data->ready = 0; | 278 | data->ready = 0; |
279 | /* | ||
280 | * It is necessary to thaw kernel threads here, because | ||
281 | * SNAPSHOT_CREATE_IMAGE may be invoked directly after | ||
282 | * SNAPSHOT_FREE. In that case, if kernel threads were not | ||
283 | * thawed, the preallocation of memory carried out by | ||
284 | * hibernation_snapshot() might run into problems (i.e. it | ||
285 | * might fail or even deadlock). | ||
286 | */ | ||
287 | thaw_kernel_threads(); | ||
306 | break; | 288 | break; |
307 | 289 | ||
308 | case SNAPSHOT_SET_IMAGE_SIZE: | ||
309 | snapshot_deprecated_ioctl(cmd); | ||
310 | case SNAPSHOT_PREF_IMAGE_SIZE: | 290 | case SNAPSHOT_PREF_IMAGE_SIZE: |
311 | image_size = arg; | 291 | image_size = arg; |
312 | break; | 292 | break; |
@@ -321,16 +301,12 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd, | |||
321 | error = put_user(size, (loff_t __user *)arg); | 301 | error = put_user(size, (loff_t __user *)arg); |
322 | break; | 302 | break; |
323 | 303 | ||
324 | case SNAPSHOT_AVAIL_SWAP: | ||
325 | snapshot_deprecated_ioctl(cmd); | ||
326 | case SNAPSHOT_AVAIL_SWAP_SIZE: | 304 | case SNAPSHOT_AVAIL_SWAP_SIZE: |
327 | size = count_swap_pages(data->swap, 1); | 305 | size = count_swap_pages(data->swap, 1); |
328 | size <<= PAGE_SHIFT; | 306 | size <<= PAGE_SHIFT; |
329 | error = put_user(size, (loff_t __user *)arg); | 307 | error = put_user(size, (loff_t __user *)arg); |
330 | break; | 308 | break; |
331 | 309 | ||
332 | case SNAPSHOT_GET_SWAP_PAGE: | ||
333 | snapshot_deprecated_ioctl(cmd); | ||
334 | case SNAPSHOT_ALLOC_SWAP_PAGE: | 310 | case SNAPSHOT_ALLOC_SWAP_PAGE: |
335 | if (data->swap < 0 || data->swap >= MAX_SWAPFILES) { | 311 | if (data->swap < 0 || data->swap >= MAX_SWAPFILES) { |
336 | error = -ENODEV; | 312 | error = -ENODEV; |
@@ -353,27 +329,6 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd, | |||
353 | free_all_swap_pages(data->swap); | 329 | free_all_swap_pages(data->swap); |
354 | break; | 330 | break; |
355 | 331 | ||
356 | case SNAPSHOT_SET_SWAP_FILE: /* This ioctl is deprecated */ | ||
357 | snapshot_deprecated_ioctl(cmd); | ||
358 | if (!swsusp_swap_in_use()) { | ||
359 | /* | ||
360 | * User space encodes device types as two-byte values, | ||
361 | * so we need to recode them | ||
362 | */ | ||
363 | if (old_decode_dev(arg)) { | ||
364 | data->swap = swap_type_of(old_decode_dev(arg), | ||
365 | 0, NULL); | ||
366 | if (data->swap < 0) | ||
367 | error = -ENODEV; | ||
368 | } else { | ||
369 | data->swap = -1; | ||
370 | error = -EINVAL; | ||
371 | } | ||
372 | } else { | ||
373 | error = -EPERM; | ||
374 | } | ||
375 | break; | ||
376 | |||
377 | case SNAPSHOT_S2RAM: | 332 | case SNAPSHOT_S2RAM: |
378 | if (!data->frozen) { | 333 | if (!data->frozen) { |
379 | error = -EPERM; | 334 | error = -EPERM; |
@@ -396,33 +351,6 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd, | |||
396 | error = hibernation_platform_enter(); | 351 | error = hibernation_platform_enter(); |
397 | break; | 352 | break; |
398 | 353 | ||
399 | case SNAPSHOT_PMOPS: /* This ioctl is deprecated */ | ||
400 | snapshot_deprecated_ioctl(cmd); | ||
401 | error = -EINVAL; | ||
402 | |||
403 | switch (arg) { | ||
404 | |||
405 | case PMOPS_PREPARE: | ||
406 | data->platform_support = 1; | ||
407 | error = 0; | ||
408 | break; | ||
409 | |||
410 | case PMOPS_ENTER: | ||
411 | if (data->platform_support) | ||
412 | error = hibernation_platform_enter(); | ||
413 | break; | ||
414 | |||
415 | case PMOPS_FINISH: | ||
416 | if (data->platform_support) | ||
417 | error = 0; | ||
418 | break; | ||
419 | |||
420 | default: | ||
421 | printk(KERN_ERR "SNAPSHOT_PMOPS: invalid argument %ld\n", arg); | ||
422 | |||
423 | } | ||
424 | break; | ||
425 | |||
426 | case SNAPSHOT_SET_SWAP_AREA: | 354 | case SNAPSHOT_SET_SWAP_AREA: |
427 | if (swsusp_swap_in_use()) { | 355 | if (swsusp_swap_in_use()) { |
428 | error = -EPERM; | 356 | error = -EPERM; |
@@ -464,6 +392,66 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd, | |||
464 | return error; | 392 | return error; |
465 | } | 393 | } |
466 | 394 | ||
395 | #ifdef CONFIG_COMPAT | ||
396 | |||
397 | struct compat_resume_swap_area { | ||
398 | compat_loff_t offset; | ||
399 | u32 dev; | ||
400 | } __packed; | ||
401 | |||
402 | static long | ||
403 | snapshot_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | ||
404 | { | ||
405 | BUILD_BUG_ON(sizeof(loff_t) != sizeof(compat_loff_t)); | ||
406 | |||
407 | switch (cmd) { | ||
408 | case SNAPSHOT_GET_IMAGE_SIZE: | ||
409 | case SNAPSHOT_AVAIL_SWAP_SIZE: | ||
410 | case SNAPSHOT_ALLOC_SWAP_PAGE: { | ||
411 | compat_loff_t __user *uoffset = compat_ptr(arg); | ||
412 | loff_t offset; | ||
413 | mm_segment_t old_fs; | ||
414 | int err; | ||
415 | |||
416 | old_fs = get_fs(); | ||
417 | set_fs(KERNEL_DS); | ||
418 | err = snapshot_ioctl(file, cmd, (unsigned long) &offset); | ||
419 | set_fs(old_fs); | ||
420 | if (!err && put_user(offset, uoffset)) | ||
421 | err = -EFAULT; | ||
422 | return err; | ||
423 | } | ||
424 | |||
425 | case SNAPSHOT_CREATE_IMAGE: | ||
426 | return snapshot_ioctl(file, cmd, | ||
427 | (unsigned long) compat_ptr(arg)); | ||
428 | |||
429 | case SNAPSHOT_SET_SWAP_AREA: { | ||
430 | struct compat_resume_swap_area __user *u_swap_area = | ||
431 | compat_ptr(arg); | ||
432 | struct resume_swap_area swap_area; | ||
433 | mm_segment_t old_fs; | ||
434 | int err; | ||
435 | |||
436 | err = get_user(swap_area.offset, &u_swap_area->offset); | ||
437 | err |= get_user(swap_area.dev, &u_swap_area->dev); | ||
438 | if (err) | ||
439 | return -EFAULT; | ||
440 | old_fs = get_fs(); | ||
441 | set_fs(KERNEL_DS); | ||
442 | err = snapshot_ioctl(file, SNAPSHOT_SET_SWAP_AREA, | ||
443 | (unsigned long) &swap_area); | ||
444 | set_fs(old_fs); | ||
445 | return err; | ||
446 | } | ||
447 | |||
448 | default: | ||
449 | return snapshot_ioctl(file, cmd, arg); | ||
450 | } | ||
451 | } | ||
452 | |||
453 | #endif /* CONFIG_COMPAT */ | ||
454 | |||
467 | static const struct file_operations snapshot_fops = { | 455 | static const struct file_operations snapshot_fops = { |
468 | .open = snapshot_open, | 456 | .open = snapshot_open, |
469 | .release = snapshot_release, | 457 | .release = snapshot_release, |
@@ -471,6 +459,9 @@ static const struct file_operations snapshot_fops = { | |||
471 | .write = snapshot_write, | 459 | .write = snapshot_write, |
472 | .llseek = no_llseek, | 460 | .llseek = no_llseek, |
473 | .unlocked_ioctl = snapshot_ioctl, | 461 | .unlocked_ioctl = snapshot_ioctl, |
462 | #ifdef CONFIG_COMPAT | ||
463 | .compat_ioctl = snapshot_compat_ioctl, | ||
464 | #endif | ||
474 | }; | 465 | }; |
475 | 466 | ||
476 | static struct miscdevice snapshot_device = { | 467 | static struct miscdevice snapshot_device = { |