diff options
author | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
---|---|---|
committer | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
commit | ada47b5fe13d89735805b566185f4885f5a3f750 (patch) | |
tree | 644b88f8a71896307d71438e9b3af49126ffb22b /kernel/power | |
parent | 43e98717ad40a4ae64545b5ba047c7b86aa44f4f (diff) | |
parent | 3280f21d43ee541f97f8cda5792150d2dbec20d5 (diff) |
Merge branch 'wip-2.6.34' into old-private-masterarchived-private-master
Diffstat (limited to 'kernel/power')
-rw-r--r-- | kernel/power/Kconfig | 19 | ||||
-rw-r--r-- | kernel/power/Makefile | 2 | ||||
-rw-r--r-- | kernel/power/console.c | 7 | ||||
-rw-r--r-- | kernel/power/hibernate.c | 40 | ||||
-rw-r--r-- | kernel/power/hibernate_nvs.c | 1 | ||||
-rw-r--r-- | kernel/power/main.c | 32 | ||||
-rw-r--r-- | kernel/power/process.c | 19 | ||||
-rw-r--r-- | kernel/power/snapshot.c | 5 | ||||
-rw-r--r-- | kernel/power/suspend.c | 4 | ||||
-rw-r--r-- | kernel/power/swap.c | 112 | ||||
-rw-r--r-- | kernel/power/swsusp.c | 188 | ||||
-rw-r--r-- | kernel/power/user.c | 25 |
12 files changed, 239 insertions, 215 deletions
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig index 91e09d3b2eb2..5c36ea9d55d2 100644 --- a/kernel/power/Kconfig +++ b/kernel/power/Kconfig | |||
@@ -27,6 +27,15 @@ config PM_DEBUG | |||
27 | code. This is helpful when debugging and reporting PM bugs, like | 27 | code. This is helpful when debugging and reporting PM bugs, like |
28 | suspend support. | 28 | suspend support. |
29 | 29 | ||
30 | config PM_ADVANCED_DEBUG | ||
31 | bool "Extra PM attributes in sysfs for low-level debugging/testing" | ||
32 | depends on PM_DEBUG | ||
33 | default n | ||
34 | ---help--- | ||
35 | Add extra sysfs attributes allowing one to access some Power Management | ||
36 | fields of device objects from user space. If you are not a kernel | ||
37 | developer interested in debugging/testing Power Management, say "no". | ||
38 | |||
30 | config PM_VERBOSE | 39 | config PM_VERBOSE |
31 | bool "Verbose Power Management debugging" | 40 | bool "Verbose Power Management debugging" |
32 | depends on PM_DEBUG | 41 | depends on PM_DEBUG |
@@ -85,6 +94,11 @@ config PM_SLEEP | |||
85 | depends on SUSPEND || HIBERNATION || XEN_SAVE_RESTORE | 94 | depends on SUSPEND || HIBERNATION || XEN_SAVE_RESTORE |
86 | default y | 95 | default y |
87 | 96 | ||
97 | config PM_SLEEP_ADVANCED_DEBUG | ||
98 | bool | ||
99 | depends on PM_ADVANCED_DEBUG | ||
100 | default n | ||
101 | |||
88 | config SUSPEND | 102 | config SUSPEND |
89 | bool "Suspend to RAM and standby" | 103 | bool "Suspend to RAM and standby" |
90 | depends on PM && ARCH_SUSPEND_POSSIBLE | 104 | depends on PM && ARCH_SUSPEND_POSSIBLE |
@@ -222,3 +236,8 @@ config PM_RUNTIME | |||
222 | and the bus type drivers of the buses the devices are on are | 236 | and the bus type drivers of the buses the devices are on are |
223 | responsible for the actual handling of the autosuspend requests and | 237 | responsible for the actual handling of the autosuspend requests and |
224 | wake-up events. | 238 | wake-up events. |
239 | |||
240 | config PM_OPS | ||
241 | bool | ||
242 | depends on PM_SLEEP || PM_RUNTIME | ||
243 | default y | ||
diff --git a/kernel/power/Makefile b/kernel/power/Makefile index c3b81c30e5d5..43191815f874 100644 --- a/kernel/power/Makefile +++ b/kernel/power/Makefile | |||
@@ -8,7 +8,7 @@ obj-$(CONFIG_PM_SLEEP) += console.o | |||
8 | obj-$(CONFIG_FREEZER) += process.o | 8 | obj-$(CONFIG_FREEZER) += process.o |
9 | obj-$(CONFIG_SUSPEND) += suspend.o | 9 | obj-$(CONFIG_SUSPEND) += suspend.o |
10 | obj-$(CONFIG_PM_TEST_SUSPEND) += suspend_test.o | 10 | obj-$(CONFIG_PM_TEST_SUSPEND) += suspend_test.o |
11 | obj-$(CONFIG_HIBERNATION) += swsusp.o hibernate.o snapshot.o swap.o user.o | 11 | obj-$(CONFIG_HIBERNATION) += hibernate.o snapshot.o swap.o user.o |
12 | obj-$(CONFIG_HIBERNATION_NVS) += hibernate_nvs.o | 12 | obj-$(CONFIG_HIBERNATION_NVS) += hibernate_nvs.o |
13 | 13 | ||
14 | obj-$(CONFIG_MAGIC_SYSRQ) += poweroff.o | 14 | obj-$(CONFIG_MAGIC_SYSRQ) += poweroff.o |
diff --git a/kernel/power/console.c b/kernel/power/console.c index 5187136fe1de..218e5af90156 100644 --- a/kernel/power/console.c +++ b/kernel/power/console.c | |||
@@ -6,7 +6,7 @@ | |||
6 | 6 | ||
7 | #include <linux/vt_kern.h> | 7 | #include <linux/vt_kern.h> |
8 | #include <linux/kbd_kern.h> | 8 | #include <linux/kbd_kern.h> |
9 | #include <linux/console.h> | 9 | #include <linux/vt.h> |
10 | #include <linux/module.h> | 10 | #include <linux/module.h> |
11 | #include "power.h" | 11 | #include "power.h" |
12 | 12 | ||
@@ -21,8 +21,7 @@ int pm_prepare_console(void) | |||
21 | if (orig_fgconsole < 0) | 21 | if (orig_fgconsole < 0) |
22 | return 1; | 22 | return 1; |
23 | 23 | ||
24 | orig_kmsg = kmsg_redirect; | 24 | orig_kmsg = vt_kmsg_redirect(SUSPEND_CONSOLE); |
25 | kmsg_redirect = SUSPEND_CONSOLE; | ||
26 | return 0; | 25 | return 0; |
27 | } | 26 | } |
28 | 27 | ||
@@ -30,7 +29,7 @@ void pm_restore_console(void) | |||
30 | { | 29 | { |
31 | if (orig_fgconsole >= 0) { | 30 | if (orig_fgconsole >= 0) { |
32 | vt_move_to_console(orig_fgconsole, 0); | 31 | vt_move_to_console(orig_fgconsole, 0); |
33 | kmsg_redirect = orig_kmsg; | 32 | vt_kmsg_redirect(orig_kmsg); |
34 | } | 33 | } |
35 | } | 34 | } |
36 | #endif | 35 | #endif |
diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c index 04a9e90d248f..aa9e916da4d5 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/console.h> | 22 | #include <linux/console.h> |
23 | #include <linux/cpu.h> | 23 | #include <linux/cpu.h> |
24 | #include <linux/freezer.h> | 24 | #include <linux/freezer.h> |
25 | #include <linux/gfp.h> | ||
25 | #include <scsi/scsi_scan.h> | 26 | #include <scsi/scsi_scan.h> |
26 | #include <asm/suspend.h> | 27 | #include <asm/suspend.h> |
27 | 28 | ||
@@ -32,6 +33,7 @@ static int noresume = 0; | |||
32 | static char resume_file[256] = CONFIG_PM_STD_PARTITION; | 33 | static char resume_file[256] = CONFIG_PM_STD_PARTITION; |
33 | dev_t swsusp_resume_device; | 34 | dev_t swsusp_resume_device; |
34 | sector_t swsusp_resume_block; | 35 | sector_t swsusp_resume_block; |
36 | int in_suspend __nosavedata = 0; | ||
35 | 37 | ||
36 | enum { | 38 | enum { |
37 | HIBERNATION_INVALID, | 39 | HIBERNATION_INVALID, |
@@ -202,6 +204,35 @@ static void platform_recover(int platform_mode) | |||
202 | } | 204 | } |
203 | 205 | ||
204 | /** | 206 | /** |
207 | * swsusp_show_speed - print the time elapsed between two events. | ||
208 | * @start: Starting event. | ||
209 | * @stop: Final event. | ||
210 | * @nr_pages - number of pages processed between @start and @stop | ||
211 | * @msg - introductory message to print | ||
212 | */ | ||
213 | |||
214 | void swsusp_show_speed(struct timeval *start, struct timeval *stop, | ||
215 | unsigned nr_pages, char *msg) | ||
216 | { | ||
217 | s64 elapsed_centisecs64; | ||
218 | int centisecs; | ||
219 | int k; | ||
220 | int kps; | ||
221 | |||
222 | elapsed_centisecs64 = timeval_to_ns(stop) - timeval_to_ns(start); | ||
223 | do_div(elapsed_centisecs64, NSEC_PER_SEC / 100); | ||
224 | centisecs = elapsed_centisecs64; | ||
225 | if (centisecs == 0) | ||
226 | centisecs = 1; /* avoid div-by-zero */ | ||
227 | k = nr_pages * (PAGE_SIZE / 1024); | ||
228 | kps = (k * 100) / centisecs; | ||
229 | printk(KERN_INFO "PM: %s %d kbytes in %d.%02d seconds (%d.%02d MB/s)\n", | ||
230 | msg, k, | ||
231 | centisecs / 100, centisecs % 100, | ||
232 | kps / 1000, (kps % 1000) / 10); | ||
233 | } | ||
234 | |||
235 | /** | ||
205 | * create_image - freeze devices that need to be frozen with interrupts | 236 | * create_image - freeze devices that need to be frozen with interrupts |
206 | * off, create the hibernation image and thaw those devices. Control | 237 | * off, create the hibernation image and thaw those devices. Control |
207 | * reappears in this routine after a restore. | 238 | * reappears in this routine after a restore. |
@@ -293,6 +324,7 @@ static int create_image(int platform_mode) | |||
293 | int hibernation_snapshot(int platform_mode) | 324 | int hibernation_snapshot(int platform_mode) |
294 | { | 325 | { |
295 | int error; | 326 | int error; |
327 | gfp_t saved_mask; | ||
296 | 328 | ||
297 | error = platform_begin(platform_mode); | 329 | error = platform_begin(platform_mode); |
298 | if (error) | 330 | if (error) |
@@ -304,6 +336,7 @@ int hibernation_snapshot(int platform_mode) | |||
304 | goto Close; | 336 | goto Close; |
305 | 337 | ||
306 | suspend_console(); | 338 | suspend_console(); |
339 | saved_mask = clear_gfp_allowed_mask(GFP_IOFS); | ||
307 | error = dpm_suspend_start(PMSG_FREEZE); | 340 | error = dpm_suspend_start(PMSG_FREEZE); |
308 | if (error) | 341 | if (error) |
309 | goto Recover_platform; | 342 | goto Recover_platform; |
@@ -321,6 +354,7 @@ int hibernation_snapshot(int platform_mode) | |||
321 | 354 | ||
322 | dpm_resume_end(in_suspend ? | 355 | dpm_resume_end(in_suspend ? |
323 | (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE); | 356 | (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE); |
357 | set_gfp_allowed_mask(saved_mask); | ||
324 | resume_console(); | 358 | resume_console(); |
325 | Close: | 359 | Close: |
326 | platform_end(platform_mode); | 360 | platform_end(platform_mode); |
@@ -415,14 +449,17 @@ static int resume_target_kernel(bool platform_mode) | |||
415 | int hibernation_restore(int platform_mode) | 449 | int hibernation_restore(int platform_mode) |
416 | { | 450 | { |
417 | int error; | 451 | int error; |
452 | gfp_t saved_mask; | ||
418 | 453 | ||
419 | pm_prepare_console(); | 454 | pm_prepare_console(); |
420 | suspend_console(); | 455 | suspend_console(); |
456 | saved_mask = clear_gfp_allowed_mask(GFP_IOFS); | ||
421 | error = dpm_suspend_start(PMSG_QUIESCE); | 457 | error = dpm_suspend_start(PMSG_QUIESCE); |
422 | if (!error) { | 458 | if (!error) { |
423 | error = resume_target_kernel(platform_mode); | 459 | error = resume_target_kernel(platform_mode); |
424 | dpm_resume_end(PMSG_RECOVER); | 460 | dpm_resume_end(PMSG_RECOVER); |
425 | } | 461 | } |
462 | set_gfp_allowed_mask(saved_mask); | ||
426 | resume_console(); | 463 | resume_console(); |
427 | pm_restore_console(); | 464 | pm_restore_console(); |
428 | return error; | 465 | return error; |
@@ -436,6 +473,7 @@ int hibernation_restore(int platform_mode) | |||
436 | int hibernation_platform_enter(void) | 473 | int hibernation_platform_enter(void) |
437 | { | 474 | { |
438 | int error; | 475 | int error; |
476 | gfp_t saved_mask; | ||
439 | 477 | ||
440 | if (!hibernation_ops) | 478 | if (!hibernation_ops) |
441 | return -ENOSYS; | 479 | return -ENOSYS; |
@@ -451,6 +489,7 @@ int hibernation_platform_enter(void) | |||
451 | 489 | ||
452 | entering_platform_hibernation = true; | 490 | entering_platform_hibernation = true; |
453 | suspend_console(); | 491 | suspend_console(); |
492 | saved_mask = clear_gfp_allowed_mask(GFP_IOFS); | ||
454 | error = dpm_suspend_start(PMSG_HIBERNATE); | 493 | error = dpm_suspend_start(PMSG_HIBERNATE); |
455 | if (error) { | 494 | if (error) { |
456 | if (hibernation_ops->recover) | 495 | if (hibernation_ops->recover) |
@@ -488,6 +527,7 @@ int hibernation_platform_enter(void) | |||
488 | Resume_devices: | 527 | Resume_devices: |
489 | entering_platform_hibernation = false; | 528 | entering_platform_hibernation = false; |
490 | dpm_resume_end(PMSG_RESTORE); | 529 | dpm_resume_end(PMSG_RESTORE); |
530 | set_gfp_allowed_mask(saved_mask); | ||
491 | resume_console(); | 531 | resume_console(); |
492 | 532 | ||
493 | Close: | 533 | Close: |
diff --git a/kernel/power/hibernate_nvs.c b/kernel/power/hibernate_nvs.c index 39ac698ef836..fdcad9ed5a7b 100644 --- a/kernel/power/hibernate_nvs.c +++ b/kernel/power/hibernate_nvs.c | |||
@@ -10,6 +10,7 @@ | |||
10 | #include <linux/kernel.h> | 10 | #include <linux/kernel.h> |
11 | #include <linux/list.h> | 11 | #include <linux/list.h> |
12 | #include <linux/mm.h> | 12 | #include <linux/mm.h> |
13 | #include <linux/slab.h> | ||
13 | #include <linux/suspend.h> | 14 | #include <linux/suspend.h> |
14 | 15 | ||
15 | /* | 16 | /* |
diff --git a/kernel/power/main.c b/kernel/power/main.c index 347d2cc88cd0..b58800b21fc0 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c | |||
@@ -44,6 +44,32 @@ int pm_notifier_call_chain(unsigned long val) | |||
44 | == NOTIFY_BAD) ? -EINVAL : 0; | 44 | == NOTIFY_BAD) ? -EINVAL : 0; |
45 | } | 45 | } |
46 | 46 | ||
47 | /* If set, devices may be suspended and resumed asynchronously. */ | ||
48 | int pm_async_enabled = 1; | ||
49 | |||
50 | static ssize_t pm_async_show(struct kobject *kobj, struct kobj_attribute *attr, | ||
51 | char *buf) | ||
52 | { | ||
53 | return sprintf(buf, "%d\n", pm_async_enabled); | ||
54 | } | ||
55 | |||
56 | static ssize_t pm_async_store(struct kobject *kobj, struct kobj_attribute *attr, | ||
57 | const char *buf, size_t n) | ||
58 | { | ||
59 | unsigned long val; | ||
60 | |||
61 | if (strict_strtoul(buf, 10, &val)) | ||
62 | return -EINVAL; | ||
63 | |||
64 | if (val > 1) | ||
65 | return -EINVAL; | ||
66 | |||
67 | pm_async_enabled = val; | ||
68 | return n; | ||
69 | } | ||
70 | |||
71 | power_attr(pm_async); | ||
72 | |||
47 | #ifdef CONFIG_PM_DEBUG | 73 | #ifdef CONFIG_PM_DEBUG |
48 | int pm_test_level = TEST_NONE; | 74 | int pm_test_level = TEST_NONE; |
49 | 75 | ||
@@ -208,9 +234,12 @@ static struct attribute * g[] = { | |||
208 | #ifdef CONFIG_PM_TRACE | 234 | #ifdef CONFIG_PM_TRACE |
209 | &pm_trace_attr.attr, | 235 | &pm_trace_attr.attr, |
210 | #endif | 236 | #endif |
211 | #if defined(CONFIG_PM_SLEEP) && defined(CONFIG_PM_DEBUG) | 237 | #ifdef CONFIG_PM_SLEEP |
238 | &pm_async_attr.attr, | ||
239 | #ifdef CONFIG_PM_DEBUG | ||
212 | &pm_test_attr.attr, | 240 | &pm_test_attr.attr, |
213 | #endif | 241 | #endif |
242 | #endif | ||
214 | NULL, | 243 | NULL, |
215 | }; | 244 | }; |
216 | 245 | ||
@@ -220,6 +249,7 @@ static struct attribute_group attr_group = { | |||
220 | 249 | ||
221 | #ifdef CONFIG_PM_RUNTIME | 250 | #ifdef CONFIG_PM_RUNTIME |
222 | struct workqueue_struct *pm_wq; | 251 | struct workqueue_struct *pm_wq; |
252 | EXPORT_SYMBOL_GPL(pm_wq); | ||
223 | 253 | ||
224 | static int __init pm_start_workqueue(void) | 254 | static int __init pm_start_workqueue(void) |
225 | { | 255 | { |
diff --git a/kernel/power/process.c b/kernel/power/process.c index cc2e55373b68..71ae29052ab6 100644 --- a/kernel/power/process.c +++ b/kernel/power/process.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/module.h> | 14 | #include <linux/module.h> |
15 | #include <linux/syscalls.h> | 15 | #include <linux/syscalls.h> |
16 | #include <linux/freezer.h> | 16 | #include <linux/freezer.h> |
17 | #include <linux/delay.h> | ||
17 | 18 | ||
18 | /* | 19 | /* |
19 | * Timeout for stopping processes | 20 | * Timeout for stopping processes |
@@ -41,7 +42,7 @@ static int try_to_freeze_tasks(bool sig_only) | |||
41 | do_gettimeofday(&start); | 42 | do_gettimeofday(&start); |
42 | 43 | ||
43 | end_time = jiffies + TIMEOUT; | 44 | end_time = jiffies + TIMEOUT; |
44 | do { | 45 | while (true) { |
45 | todo = 0; | 46 | todo = 0; |
46 | read_lock(&tasklist_lock); | 47 | read_lock(&tasklist_lock); |
47 | do_each_thread(g, p) { | 48 | do_each_thread(g, p) { |
@@ -62,10 +63,15 @@ static int try_to_freeze_tasks(bool sig_only) | |||
62 | todo++; | 63 | todo++; |
63 | } while_each_thread(g, p); | 64 | } while_each_thread(g, p); |
64 | read_unlock(&tasklist_lock); | 65 | read_unlock(&tasklist_lock); |
65 | yield(); /* Yield is okay here */ | 66 | if (!todo || time_after(jiffies, end_time)) |
66 | if (time_after(jiffies, end_time)) | ||
67 | break; | 67 | break; |
68 | } while (todo); | 68 | |
69 | /* | ||
70 | * We need to retry, but first give the freezing tasks some | ||
71 | * time to enter the regrigerator. | ||
72 | */ | ||
73 | msleep(10); | ||
74 | } | ||
69 | 75 | ||
70 | do_gettimeofday(&end); | 76 | do_gettimeofday(&end); |
71 | elapsed_csecs64 = timeval_to_ns(&end) - timeval_to_ns(&start); | 77 | elapsed_csecs64 = timeval_to_ns(&end) - timeval_to_ns(&start); |
@@ -82,12 +88,11 @@ static int try_to_freeze_tasks(bool sig_only) | |||
82 | printk(KERN_ERR "Freezing of tasks failed after %d.%02d seconds " | 88 | printk(KERN_ERR "Freezing of tasks failed after %d.%02d seconds " |
83 | "(%d tasks refusing to freeze):\n", | 89 | "(%d tasks refusing to freeze):\n", |
84 | elapsed_csecs / 100, elapsed_csecs % 100, todo); | 90 | elapsed_csecs / 100, elapsed_csecs % 100, todo); |
85 | show_state(); | ||
86 | read_lock(&tasklist_lock); | 91 | read_lock(&tasklist_lock); |
87 | do_each_thread(g, p) { | 92 | do_each_thread(g, p) { |
88 | task_lock(p); | 93 | task_lock(p); |
89 | if (freezing(p) && !freezer_should_skip(p)) | 94 | if (freezing(p) && !freezer_should_skip(p)) |
90 | printk(KERN_ERR " %s\n", p->comm); | 95 | sched_show_task(p); |
91 | cancel_freezing(p); | 96 | cancel_freezing(p); |
92 | task_unlock(p); | 97 | task_unlock(p); |
93 | } while_each_thread(g, p); | 98 | } while_each_thread(g, p); |
@@ -139,7 +144,7 @@ static void thaw_tasks(bool nosig_only) | |||
139 | if (nosig_only && should_send_signal(p)) | 144 | if (nosig_only && should_send_signal(p)) |
140 | continue; | 145 | continue; |
141 | 146 | ||
142 | if (cgroup_frozen(p)) | 147 | if (cgroup_freezing_or_frozen(p)) |
143 | continue; | 148 | continue; |
144 | 149 | ||
145 | thaw_process(p); | 150 | thaw_process(p); |
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c index 36cb168e4330..be861c26dda7 100644 --- a/kernel/power/snapshot.c +++ b/kernel/power/snapshot.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/console.h> | 26 | #include <linux/console.h> |
27 | #include <linux/highmem.h> | 27 | #include <linux/highmem.h> |
28 | #include <linux/list.h> | 28 | #include <linux/list.h> |
29 | #include <linux/slab.h> | ||
29 | 30 | ||
30 | #include <asm/uaccess.h> | 31 | #include <asm/uaccess.h> |
31 | #include <asm/mmu_context.h> | 32 | #include <asm/mmu_context.h> |
@@ -1181,7 +1182,7 @@ static void free_unnecessary_pages(void) | |||
1181 | 1182 | ||
1182 | memory_bm_position_reset(©_bm); | 1183 | memory_bm_position_reset(©_bm); |
1183 | 1184 | ||
1184 | while (to_free_normal > 0 && to_free_highmem > 0) { | 1185 | while (to_free_normal > 0 || to_free_highmem > 0) { |
1185 | unsigned long pfn = memory_bm_next_pfn(©_bm); | 1186 | unsigned long pfn = memory_bm_next_pfn(©_bm); |
1186 | struct page *page = pfn_to_page(pfn); | 1187 | struct page *page = pfn_to_page(pfn); |
1187 | 1188 | ||
@@ -1500,7 +1501,7 @@ asmlinkage int swsusp_save(void) | |||
1500 | { | 1501 | { |
1501 | unsigned int nr_pages, nr_highmem; | 1502 | unsigned int nr_pages, nr_highmem; |
1502 | 1503 | ||
1503 | printk(KERN_INFO "PM: Creating hibernation image: \n"); | 1504 | printk(KERN_INFO "PM: Creating hibernation image:\n"); |
1504 | 1505 | ||
1505 | drain_local_pages(NULL); | 1506 | drain_local_pages(NULL); |
1506 | nr_pages = count_data_pages(); | 1507 | nr_pages = count_data_pages(); |
diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index 6f10dfc2d3e9..56e7dbb8b996 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/console.h> | 15 | #include <linux/console.h> |
16 | #include <linux/cpu.h> | 16 | #include <linux/cpu.h> |
17 | #include <linux/syscalls.h> | 17 | #include <linux/syscalls.h> |
18 | #include <linux/gfp.h> | ||
18 | 19 | ||
19 | #include "power.h" | 20 | #include "power.h" |
20 | 21 | ||
@@ -189,6 +190,7 @@ static int suspend_enter(suspend_state_t state) | |||
189 | int suspend_devices_and_enter(suspend_state_t state) | 190 | int suspend_devices_and_enter(suspend_state_t state) |
190 | { | 191 | { |
191 | int error; | 192 | int error; |
193 | gfp_t saved_mask; | ||
192 | 194 | ||
193 | if (!suspend_ops) | 195 | if (!suspend_ops) |
194 | return -ENOSYS; | 196 | return -ENOSYS; |
@@ -199,6 +201,7 @@ int suspend_devices_and_enter(suspend_state_t state) | |||
199 | goto Close; | 201 | goto Close; |
200 | } | 202 | } |
201 | suspend_console(); | 203 | suspend_console(); |
204 | saved_mask = clear_gfp_allowed_mask(GFP_IOFS); | ||
202 | suspend_test_start(); | 205 | suspend_test_start(); |
203 | error = dpm_suspend_start(PMSG_SUSPEND); | 206 | error = dpm_suspend_start(PMSG_SUSPEND); |
204 | if (error) { | 207 | if (error) { |
@@ -215,6 +218,7 @@ int suspend_devices_and_enter(suspend_state_t state) | |||
215 | suspend_test_start(); | 218 | suspend_test_start(); |
216 | dpm_resume_end(PMSG_RESUME); | 219 | dpm_resume_end(PMSG_RESUME); |
217 | suspend_test_finish("resume devices"); | 220 | suspend_test_finish("resume devices"); |
221 | set_gfp_allowed_mask(saved_mask); | ||
218 | resume_console(); | 222 | resume_console(); |
219 | Close: | 223 | Close: |
220 | if (suspend_ops->end) | 224 | if (suspend_ops->end) |
diff --git a/kernel/power/swap.c b/kernel/power/swap.c index 890f6b11b1d3..66824d71983a 100644 --- a/kernel/power/swap.c +++ b/kernel/power/swap.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/swap.h> | 23 | #include <linux/swap.h> |
24 | #include <linux/swapops.h> | 24 | #include <linux/swapops.h> |
25 | #include <linux/pm.h> | 25 | #include <linux/pm.h> |
26 | #include <linux/slab.h> | ||
26 | 27 | ||
27 | #include "power.h" | 28 | #include "power.h" |
28 | 29 | ||
@@ -38,6 +39,107 @@ struct swsusp_header { | |||
38 | 39 | ||
39 | static struct swsusp_header *swsusp_header; | 40 | static struct swsusp_header *swsusp_header; |
40 | 41 | ||
42 | /** | ||
43 | * The following functions are used for tracing the allocated | ||
44 | * swap pages, so that they can be freed in case of an error. | ||
45 | */ | ||
46 | |||
47 | struct swsusp_extent { | ||
48 | struct rb_node node; | ||
49 | unsigned long start; | ||
50 | unsigned long end; | ||
51 | }; | ||
52 | |||
53 | static struct rb_root swsusp_extents = RB_ROOT; | ||
54 | |||
55 | static int swsusp_extents_insert(unsigned long swap_offset) | ||
56 | { | ||
57 | struct rb_node **new = &(swsusp_extents.rb_node); | ||
58 | struct rb_node *parent = NULL; | ||
59 | struct swsusp_extent *ext; | ||
60 | |||
61 | /* Figure out where to put the new node */ | ||
62 | while (*new) { | ||
63 | ext = container_of(*new, struct swsusp_extent, node); | ||
64 | parent = *new; | ||
65 | if (swap_offset < ext->start) { | ||
66 | /* Try to merge */ | ||
67 | if (swap_offset == ext->start - 1) { | ||
68 | ext->start--; | ||
69 | return 0; | ||
70 | } | ||
71 | new = &((*new)->rb_left); | ||
72 | } else if (swap_offset > ext->end) { | ||
73 | /* Try to merge */ | ||
74 | if (swap_offset == ext->end + 1) { | ||
75 | ext->end++; | ||
76 | return 0; | ||
77 | } | ||
78 | new = &((*new)->rb_right); | ||
79 | } else { | ||
80 | /* It already is in the tree */ | ||
81 | return -EINVAL; | ||
82 | } | ||
83 | } | ||
84 | /* Add the new node and rebalance the tree. */ | ||
85 | ext = kzalloc(sizeof(struct swsusp_extent), GFP_KERNEL); | ||
86 | if (!ext) | ||
87 | return -ENOMEM; | ||
88 | |||
89 | ext->start = swap_offset; | ||
90 | ext->end = swap_offset; | ||
91 | rb_link_node(&ext->node, parent, new); | ||
92 | rb_insert_color(&ext->node, &swsusp_extents); | ||
93 | return 0; | ||
94 | } | ||
95 | |||
96 | /** | ||
97 | * alloc_swapdev_block - allocate a swap page and register that it has | ||
98 | * been allocated, so that it can be freed in case of an error. | ||
99 | */ | ||
100 | |||
101 | sector_t alloc_swapdev_block(int swap) | ||
102 | { | ||
103 | unsigned long offset; | ||
104 | |||
105 | offset = swp_offset(get_swap_page_of_type(swap)); | ||
106 | if (offset) { | ||
107 | if (swsusp_extents_insert(offset)) | ||
108 | swap_free(swp_entry(swap, offset)); | ||
109 | else | ||
110 | return swapdev_block(swap, offset); | ||
111 | } | ||
112 | return 0; | ||
113 | } | ||
114 | |||
115 | /** | ||
116 | * free_all_swap_pages - free swap pages allocated for saving image data. | ||
117 | * It also frees the extents used to register which swap entres had been | ||
118 | * allocated. | ||
119 | */ | ||
120 | |||
121 | void free_all_swap_pages(int swap) | ||
122 | { | ||
123 | struct rb_node *node; | ||
124 | |||
125 | while ((node = swsusp_extents.rb_node)) { | ||
126 | struct swsusp_extent *ext; | ||
127 | unsigned long offset; | ||
128 | |||
129 | ext = container_of(node, struct swsusp_extent, node); | ||
130 | rb_erase(node, &swsusp_extents); | ||
131 | for (offset = ext->start; offset <= ext->end; offset++) | ||
132 | swap_free(swp_entry(swap, offset)); | ||
133 | |||
134 | kfree(ext); | ||
135 | } | ||
136 | } | ||
137 | |||
138 | int swsusp_swap_in_use(void) | ||
139 | { | ||
140 | return (swsusp_extents.rb_node != NULL); | ||
141 | } | ||
142 | |||
41 | /* | 143 | /* |
42 | * General things | 144 | * General things |
43 | */ | 145 | */ |
@@ -336,7 +438,7 @@ static int save_image(struct swap_map_handle *handle, | |||
336 | if (ret) | 438 | if (ret) |
337 | break; | 439 | break; |
338 | if (!(nr_pages % m)) | 440 | if (!(nr_pages % m)) |
339 | printk("\b\b\b\b%3d%%", nr_pages / m); | 441 | printk(KERN_CONT "\b\b\b\b%3d%%", nr_pages / m); |
340 | nr_pages++; | 442 | nr_pages++; |
341 | } | 443 | } |
342 | err2 = wait_on_bio_chain(&bio); | 444 | err2 = wait_on_bio_chain(&bio); |
@@ -344,9 +446,9 @@ static int save_image(struct swap_map_handle *handle, | |||
344 | if (!ret) | 446 | if (!ret) |
345 | ret = err2; | 447 | ret = err2; |
346 | if (!ret) | 448 | if (!ret) |
347 | printk("\b\b\b\bdone\n"); | 449 | printk(KERN_CONT "\b\b\b\bdone\n"); |
348 | else | 450 | else |
349 | printk("\n"); | 451 | printk(KERN_CONT "\n"); |
350 | swsusp_show_speed(&start, &stop, nr_to_write, "Wrote"); | 452 | swsusp_show_speed(&start, &stop, nr_to_write, "Wrote"); |
351 | return ret; | 453 | return ret; |
352 | } | 454 | } |
@@ -556,10 +658,6 @@ int swsusp_read(unsigned int *flags_p) | |||
556 | struct swsusp_info *header; | 658 | struct swsusp_info *header; |
557 | 659 | ||
558 | *flags_p = swsusp_header->flags; | 660 | *flags_p = swsusp_header->flags; |
559 | if (IS_ERR(resume_bdev)) { | ||
560 | pr_debug("PM: Image device not initialised\n"); | ||
561 | return PTR_ERR(resume_bdev); | ||
562 | } | ||
563 | 661 | ||
564 | memset(&snapshot, 0, sizeof(struct snapshot_handle)); | 662 | memset(&snapshot, 0, sizeof(struct snapshot_handle)); |
565 | error = snapshot_write_next(&snapshot, PAGE_SIZE); | 663 | error = snapshot_write_next(&snapshot, PAGE_SIZE); |
diff --git a/kernel/power/swsusp.c b/kernel/power/swsusp.c deleted file mode 100644 index 6a07f4dbf2f8..000000000000 --- a/kernel/power/swsusp.c +++ /dev/null | |||
@@ -1,188 +0,0 @@ | |||
1 | /* | ||
2 | * linux/kernel/power/swsusp.c | ||
3 | * | ||
4 | * This file provides code to write suspend image to swap and read it back. | ||
5 | * | ||
6 | * Copyright (C) 1998-2001 Gabor Kuti <seasons@fornax.hu> | ||
7 | * Copyright (C) 1998,2001-2005 Pavel Machek <pavel@suse.cz> | ||
8 | * | ||
9 | * This file is released under the GPLv2. | ||
10 | * | ||
11 | * I'd like to thank the following people for their work: | ||
12 | * | ||
13 | * Pavel Machek <pavel@ucw.cz>: | ||
14 | * Modifications, defectiveness pointing, being with me at the very beginning, | ||
15 | * suspend to swap space, stop all tasks. Port to 2.4.18-ac and 2.5.17. | ||
16 | * | ||
17 | * Steve Doddi <dirk@loth.demon.co.uk>: | ||
18 | * Support the possibility of hardware state restoring. | ||
19 | * | ||
20 | * Raph <grey.havens@earthling.net>: | ||
21 | * Support for preserving states of network devices and virtual console | ||
22 | * (including X and svgatextmode) | ||
23 | * | ||
24 | * Kurt Garloff <garloff@suse.de>: | ||
25 | * Straightened the critical function in order to prevent compilers from | ||
26 | * playing tricks with local variables. | ||
27 | * | ||
28 | * Andreas Mohr <a.mohr@mailto.de> | ||
29 | * | ||
30 | * Alex Badea <vampire@go.ro>: | ||
31 | * Fixed runaway init | ||
32 | * | ||
33 | * Rafael J. Wysocki <rjw@sisk.pl> | ||
34 | * Reworked the freeing of memory and the handling of swap | ||
35 | * | ||
36 | * More state savers are welcome. Especially for the scsi layer... | ||
37 | * | ||
38 | * For TODOs,FIXMEs also look in Documentation/power/swsusp.txt | ||
39 | */ | ||
40 | |||
41 | #include <linux/mm.h> | ||
42 | #include <linux/suspend.h> | ||
43 | #include <linux/spinlock.h> | ||
44 | #include <linux/kernel.h> | ||
45 | #include <linux/major.h> | ||
46 | #include <linux/swap.h> | ||
47 | #include <linux/pm.h> | ||
48 | #include <linux/swapops.h> | ||
49 | #include <linux/bootmem.h> | ||
50 | #include <linux/syscalls.h> | ||
51 | #include <linux/highmem.h> | ||
52 | #include <linux/time.h> | ||
53 | #include <linux/rbtree.h> | ||
54 | #include <linux/io.h> | ||
55 | |||
56 | #include "power.h" | ||
57 | |||
58 | int in_suspend __nosavedata = 0; | ||
59 | |||
60 | /** | ||
61 | * The following functions are used for tracing the allocated | ||
62 | * swap pages, so that they can be freed in case of an error. | ||
63 | */ | ||
64 | |||
65 | struct swsusp_extent { | ||
66 | struct rb_node node; | ||
67 | unsigned long start; | ||
68 | unsigned long end; | ||
69 | }; | ||
70 | |||
71 | static struct rb_root swsusp_extents = RB_ROOT; | ||
72 | |||
73 | static int swsusp_extents_insert(unsigned long swap_offset) | ||
74 | { | ||
75 | struct rb_node **new = &(swsusp_extents.rb_node); | ||
76 | struct rb_node *parent = NULL; | ||
77 | struct swsusp_extent *ext; | ||
78 | |||
79 | /* Figure out where to put the new node */ | ||
80 | while (*new) { | ||
81 | ext = container_of(*new, struct swsusp_extent, node); | ||
82 | parent = *new; | ||
83 | if (swap_offset < ext->start) { | ||
84 | /* Try to merge */ | ||
85 | if (swap_offset == ext->start - 1) { | ||
86 | ext->start--; | ||
87 | return 0; | ||
88 | } | ||
89 | new = &((*new)->rb_left); | ||
90 | } else if (swap_offset > ext->end) { | ||
91 | /* Try to merge */ | ||
92 | if (swap_offset == ext->end + 1) { | ||
93 | ext->end++; | ||
94 | return 0; | ||
95 | } | ||
96 | new = &((*new)->rb_right); | ||
97 | } else { | ||
98 | /* It already is in the tree */ | ||
99 | return -EINVAL; | ||
100 | } | ||
101 | } | ||
102 | /* Add the new node and rebalance the tree. */ | ||
103 | ext = kzalloc(sizeof(struct swsusp_extent), GFP_KERNEL); | ||
104 | if (!ext) | ||
105 | return -ENOMEM; | ||
106 | |||
107 | ext->start = swap_offset; | ||
108 | ext->end = swap_offset; | ||
109 | rb_link_node(&ext->node, parent, new); | ||
110 | rb_insert_color(&ext->node, &swsusp_extents); | ||
111 | return 0; | ||
112 | } | ||
113 | |||
114 | /** | ||
115 | * alloc_swapdev_block - allocate a swap page and register that it has | ||
116 | * been allocated, so that it can be freed in case of an error. | ||
117 | */ | ||
118 | |||
119 | sector_t alloc_swapdev_block(int swap) | ||
120 | { | ||
121 | unsigned long offset; | ||
122 | |||
123 | offset = swp_offset(get_swap_page_of_type(swap)); | ||
124 | if (offset) { | ||
125 | if (swsusp_extents_insert(offset)) | ||
126 | swap_free(swp_entry(swap, offset)); | ||
127 | else | ||
128 | return swapdev_block(swap, offset); | ||
129 | } | ||
130 | return 0; | ||
131 | } | ||
132 | |||
133 | /** | ||
134 | * free_all_swap_pages - free swap pages allocated for saving image data. | ||
135 | * It also frees the extents used to register which swap entres had been | ||
136 | * allocated. | ||
137 | */ | ||
138 | |||
139 | void free_all_swap_pages(int swap) | ||
140 | { | ||
141 | struct rb_node *node; | ||
142 | |||
143 | while ((node = swsusp_extents.rb_node)) { | ||
144 | struct swsusp_extent *ext; | ||
145 | unsigned long offset; | ||
146 | |||
147 | ext = container_of(node, struct swsusp_extent, node); | ||
148 | rb_erase(node, &swsusp_extents); | ||
149 | for (offset = ext->start; offset <= ext->end; offset++) | ||
150 | swap_free(swp_entry(swap, offset)); | ||
151 | |||
152 | kfree(ext); | ||
153 | } | ||
154 | } | ||
155 | |||
156 | int swsusp_swap_in_use(void) | ||
157 | { | ||
158 | return (swsusp_extents.rb_node != NULL); | ||
159 | } | ||
160 | |||
161 | /** | ||
162 | * swsusp_show_speed - print the time elapsed between two events represented by | ||
163 | * @start and @stop | ||
164 | * | ||
165 | * @nr_pages - number of pages processed between @start and @stop | ||
166 | * @msg - introductory message to print | ||
167 | */ | ||
168 | |||
169 | void swsusp_show_speed(struct timeval *start, struct timeval *stop, | ||
170 | unsigned nr_pages, char *msg) | ||
171 | { | ||
172 | s64 elapsed_centisecs64; | ||
173 | int centisecs; | ||
174 | int k; | ||
175 | int kps; | ||
176 | |||
177 | elapsed_centisecs64 = timeval_to_ns(stop) - timeval_to_ns(start); | ||
178 | do_div(elapsed_centisecs64, NSEC_PER_SEC / 100); | ||
179 | centisecs = elapsed_centisecs64; | ||
180 | if (centisecs == 0) | ||
181 | centisecs = 1; /* avoid div-by-zero */ | ||
182 | k = nr_pages * (PAGE_SIZE / 1024); | ||
183 | kps = (k * 100) / centisecs; | ||
184 | printk(KERN_INFO "PM: %s %d kbytes in %d.%02d seconds (%d.%02d MB/s)\n", | ||
185 | msg, k, | ||
186 | centisecs / 100, centisecs % 100, | ||
187 | kps / 1000, (kps % 1000) / 10); | ||
188 | } | ||
diff --git a/kernel/power/user.c b/kernel/power/user.c index bf0014d6a5f0..a8c96212bc1b 100644 --- a/kernel/power/user.c +++ b/kernel/power/user.c | |||
@@ -195,6 +195,15 @@ static ssize_t snapshot_write(struct file *filp, const char __user *buf, | |||
195 | return res; | 195 | return res; |
196 | } | 196 | } |
197 | 197 | ||
198 | static void snapshot_deprecated_ioctl(unsigned int cmd) | ||
199 | { | ||
200 | if (printk_ratelimit()) | ||
201 | printk(KERN_NOTICE "%pf: ioctl '%.8x' is deprecated and will " | ||
202 | "be removed soon, update your suspend-to-disk " | ||
203 | "utilities\n", | ||
204 | __builtin_return_address(0), cmd); | ||
205 | } | ||
206 | |||
198 | static long snapshot_ioctl(struct file *filp, unsigned int cmd, | 207 | static long snapshot_ioctl(struct file *filp, unsigned int cmd, |
199 | unsigned long arg) | 208 | unsigned long arg) |
200 | { | 209 | { |
@@ -246,8 +255,9 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd, | |||
246 | data->frozen = 0; | 255 | data->frozen = 0; |
247 | break; | 256 | break; |
248 | 257 | ||
249 | case SNAPSHOT_CREATE_IMAGE: | ||
250 | case SNAPSHOT_ATOMIC_SNAPSHOT: | 258 | case SNAPSHOT_ATOMIC_SNAPSHOT: |
259 | snapshot_deprecated_ioctl(cmd); | ||
260 | case SNAPSHOT_CREATE_IMAGE: | ||
251 | if (data->mode != O_RDONLY || !data->frozen || data->ready) { | 261 | if (data->mode != O_RDONLY || !data->frozen || data->ready) { |
252 | error = -EPERM; | 262 | error = -EPERM; |
253 | break; | 263 | break; |
@@ -275,8 +285,9 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd, | |||
275 | data->ready = 0; | 285 | data->ready = 0; |
276 | break; | 286 | break; |
277 | 287 | ||
278 | case SNAPSHOT_PREF_IMAGE_SIZE: | ||
279 | case SNAPSHOT_SET_IMAGE_SIZE: | 288 | case SNAPSHOT_SET_IMAGE_SIZE: |
289 | snapshot_deprecated_ioctl(cmd); | ||
290 | case SNAPSHOT_PREF_IMAGE_SIZE: | ||
280 | image_size = arg; | 291 | image_size = arg; |
281 | break; | 292 | break; |
282 | 293 | ||
@@ -290,15 +301,17 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd, | |||
290 | error = put_user(size, (loff_t __user *)arg); | 301 | error = put_user(size, (loff_t __user *)arg); |
291 | break; | 302 | break; |
292 | 303 | ||
293 | case SNAPSHOT_AVAIL_SWAP_SIZE: | ||
294 | case SNAPSHOT_AVAIL_SWAP: | 304 | case SNAPSHOT_AVAIL_SWAP: |
305 | snapshot_deprecated_ioctl(cmd); | ||
306 | case SNAPSHOT_AVAIL_SWAP_SIZE: | ||
295 | size = count_swap_pages(data->swap, 1); | 307 | size = count_swap_pages(data->swap, 1); |
296 | size <<= PAGE_SHIFT; | 308 | size <<= PAGE_SHIFT; |
297 | error = put_user(size, (loff_t __user *)arg); | 309 | error = put_user(size, (loff_t __user *)arg); |
298 | break; | 310 | break; |
299 | 311 | ||
300 | case SNAPSHOT_ALLOC_SWAP_PAGE: | ||
301 | case SNAPSHOT_GET_SWAP_PAGE: | 312 | case SNAPSHOT_GET_SWAP_PAGE: |
313 | snapshot_deprecated_ioctl(cmd); | ||
314 | case SNAPSHOT_ALLOC_SWAP_PAGE: | ||
302 | if (data->swap < 0 || data->swap >= MAX_SWAPFILES) { | 315 | if (data->swap < 0 || data->swap >= MAX_SWAPFILES) { |
303 | error = -ENODEV; | 316 | error = -ENODEV; |
304 | break; | 317 | break; |
@@ -321,6 +334,7 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd, | |||
321 | break; | 334 | break; |
322 | 335 | ||
323 | case SNAPSHOT_SET_SWAP_FILE: /* This ioctl is deprecated */ | 336 | case SNAPSHOT_SET_SWAP_FILE: /* This ioctl is deprecated */ |
337 | snapshot_deprecated_ioctl(cmd); | ||
324 | if (!swsusp_swap_in_use()) { | 338 | if (!swsusp_swap_in_use()) { |
325 | /* | 339 | /* |
326 | * User space encodes device types as two-byte values, | 340 | * User space encodes device types as two-byte values, |
@@ -362,6 +376,7 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd, | |||
362 | break; | 376 | break; |
363 | 377 | ||
364 | case SNAPSHOT_PMOPS: /* This ioctl is deprecated */ | 378 | case SNAPSHOT_PMOPS: /* This ioctl is deprecated */ |
379 | snapshot_deprecated_ioctl(cmd); | ||
365 | error = -EINVAL; | 380 | error = -EINVAL; |
366 | 381 | ||
367 | switch (arg) { | 382 | switch (arg) { |
@@ -405,7 +420,7 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd, | |||
405 | * User space encodes device types as two-byte values, | 420 | * User space encodes device types as two-byte values, |
406 | * so we need to recode them | 421 | * so we need to recode them |
407 | */ | 422 | */ |
408 | swdev = old_decode_dev(swap_area.dev); | 423 | swdev = new_decode_dev(swap_area.dev); |
409 | if (swdev) { | 424 | if (swdev) { |
410 | offset = swap_area.offset; | 425 | offset = swap_area.offset; |
411 | data->swap = swap_type_of(swdev, offset, NULL); | 426 | data->swap = swap_type_of(swdev, offset, NULL); |