aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/power
diff options
context:
space:
mode:
authorAndrea Bastoni <bastoni@cs.unc.edu>2010-05-30 19:16:45 -0400
committerAndrea Bastoni <bastoni@cs.unc.edu>2010-05-30 19:16:45 -0400
commitada47b5fe13d89735805b566185f4885f5a3f750 (patch)
tree644b88f8a71896307d71438e9b3af49126ffb22b /kernel/power
parent43e98717ad40a4ae64545b5ba047c7b86aa44f4f (diff)
parent3280f21d43ee541f97f8cda5792150d2dbec20d5 (diff)
Merge branch 'wip-2.6.34' into old-private-masterarchived-private-master
Diffstat (limited to 'kernel/power')
-rw-r--r--kernel/power/Kconfig19
-rw-r--r--kernel/power/Makefile2
-rw-r--r--kernel/power/console.c7
-rw-r--r--kernel/power/hibernate.c40
-rw-r--r--kernel/power/hibernate_nvs.c1
-rw-r--r--kernel/power/main.c32
-rw-r--r--kernel/power/process.c19
-rw-r--r--kernel/power/snapshot.c5
-rw-r--r--kernel/power/suspend.c4
-rw-r--r--kernel/power/swap.c112
-rw-r--r--kernel/power/swsusp.c188
-rw-r--r--kernel/power/user.c25
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
30config 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
30config PM_VERBOSE 39config 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
97config PM_SLEEP_ADVANCED_DEBUG
98 bool
99 depends on PM_ADVANCED_DEBUG
100 default n
101
88config SUSPEND 102config 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
240config 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
8obj-$(CONFIG_FREEZER) += process.o 8obj-$(CONFIG_FREEZER) += process.o
9obj-$(CONFIG_SUSPEND) += suspend.o 9obj-$(CONFIG_SUSPEND) += suspend.o
10obj-$(CONFIG_PM_TEST_SUSPEND) += suspend_test.o 10obj-$(CONFIG_PM_TEST_SUSPEND) += suspend_test.o
11obj-$(CONFIG_HIBERNATION) += swsusp.o hibernate.o snapshot.o swap.o user.o 11obj-$(CONFIG_HIBERNATION) += hibernate.o snapshot.o swap.o user.o
12obj-$(CONFIG_HIBERNATION_NVS) += hibernate_nvs.o 12obj-$(CONFIG_HIBERNATION_NVS) += hibernate_nvs.o
13 13
14obj-$(CONFIG_MAGIC_SYSRQ) += poweroff.o 14obj-$(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;
32static char resume_file[256] = CONFIG_PM_STD_PARTITION; 33static char resume_file[256] = CONFIG_PM_STD_PARTITION;
33dev_t swsusp_resume_device; 34dev_t swsusp_resume_device;
34sector_t swsusp_resume_block; 35sector_t swsusp_resume_block;
36int in_suspend __nosavedata = 0;
35 37
36enum { 38enum {
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
214void 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)
293int hibernation_snapshot(int platform_mode) 324int 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)
415int hibernation_restore(int platform_mode) 449int 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)
436int hibernation_platform_enter(void) 473int 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. */
48int pm_async_enabled = 1;
49
50static 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
56static 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
71power_attr(pm_async);
72
47#ifdef CONFIG_PM_DEBUG 73#ifdef CONFIG_PM_DEBUG
48int pm_test_level = TEST_NONE; 74int 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
222struct workqueue_struct *pm_wq; 251struct workqueue_struct *pm_wq;
252EXPORT_SYMBOL_GPL(pm_wq);
223 253
224static int __init pm_start_workqueue(void) 254static 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(&copy_bm); 1183 memory_bm_position_reset(&copy_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(&copy_bm); 1186 unsigned long pfn = memory_bm_next_pfn(&copy_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)
189int suspend_devices_and_enter(suspend_state_t state) 190int 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
39static struct swsusp_header *swsusp_header; 40static 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
47struct swsusp_extent {
48 struct rb_node node;
49 unsigned long start;
50 unsigned long end;
51};
52
53static struct rb_root swsusp_extents = RB_ROOT;
54
55static 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
101sector_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
121void 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
138int 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
58int 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
65struct swsusp_extent {
66 struct rb_node node;
67 unsigned long start;
68 unsigned long end;
69};
70
71static struct rb_root swsusp_extents = RB_ROOT;
72
73static 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
119sector_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
139void 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
156int 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
169void 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
198static 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
198static long snapshot_ioctl(struct file *filp, unsigned int cmd, 207static 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);