diff options
author | Len Brown <len.brown@intel.com> | 2005-09-08 01:45:47 -0400 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2005-09-08 01:45:47 -0400 |
commit | 64e47488c913ac704d465a6af86a26786d1412a5 (patch) | |
tree | d3b0148592963dcde26e4bb35ddfec8b1eaf8e23 /kernel/power | |
parent | 4a35a46bf1cda4737c428380d1db5d15e2590d18 (diff) | |
parent | caf39e87cc1182f7dae84eefc43ca14d54c78ef9 (diff) |
Merge linux-2.6 with linux-acpi-2.6
Diffstat (limited to 'kernel/power')
-rw-r--r-- | kernel/power/Kconfig | 14 | ||||
-rw-r--r-- | kernel/power/disk.c | 55 | ||||
-rw-r--r-- | kernel/power/main.c | 5 | ||||
-rw-r--r-- | kernel/power/pm.c | 3 | ||||
-rw-r--r-- | kernel/power/process.c | 29 | ||||
-rw-r--r-- | kernel/power/swsusp.c | 202 |
6 files changed, 240 insertions, 68 deletions
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig index b99f61b82685..396c7873e804 100644 --- a/kernel/power/Kconfig +++ b/kernel/power/Kconfig | |||
@@ -29,7 +29,7 @@ config PM_DEBUG | |||
29 | 29 | ||
30 | config SOFTWARE_SUSPEND | 30 | config SOFTWARE_SUSPEND |
31 | bool "Software Suspend" | 31 | bool "Software Suspend" |
32 | depends on EXPERIMENTAL && PM && SWAP && ((X86 && SMP) || ((FVR || PPC32 || X86) && !SMP)) | 32 | depends on PM && SWAP && (X86 || ((FVR || PPC32) && !SMP)) |
33 | ---help--- | 33 | ---help--- |
34 | Enable the possibility of suspending the machine. | 34 | Enable the possibility of suspending the machine. |
35 | It doesn't need APM. | 35 | It doesn't need APM. |
@@ -73,6 +73,18 @@ config PM_STD_PARTITION | |||
73 | suspended image to. It will simply pick the first available swap | 73 | suspended image to. It will simply pick the first available swap |
74 | device. | 74 | device. |
75 | 75 | ||
76 | config SWSUSP_ENCRYPT | ||
77 | bool "Encrypt suspend image" | ||
78 | depends on SOFTWARE_SUSPEND && CRYPTO=y && (CRYPTO_AES=y || CRYPTO_AES_586=y || CRYPTO_AES_X86_64=y) | ||
79 | default "" | ||
80 | ---help--- | ||
81 | To prevent data gathering from swap after resume you can encrypt | ||
82 | the suspend image with a temporary key that is deleted on | ||
83 | resume. | ||
84 | |||
85 | Note that the temporary key is stored unencrypted on disk while the | ||
86 | system is suspended. | ||
87 | |||
76 | config SUSPEND_SMP | 88 | config SUSPEND_SMP |
77 | bool | 89 | bool |
78 | depends on HOTPLUG_CPU && X86 && PM | 90 | depends on HOTPLUG_CPU && X86 && PM |
diff --git a/kernel/power/disk.c b/kernel/power/disk.c index 664eb0469b6e..2d8bf054d036 100644 --- a/kernel/power/disk.c +++ b/kernel/power/disk.c | |||
@@ -112,24 +112,12 @@ static inline void platform_finish(void) | |||
112 | } | 112 | } |
113 | } | 113 | } |
114 | 114 | ||
115 | static void finish(void) | ||
116 | { | ||
117 | device_resume(); | ||
118 | platform_finish(); | ||
119 | thaw_processes(); | ||
120 | enable_nonboot_cpus(); | ||
121 | pm_restore_console(); | ||
122 | } | ||
123 | |||
124 | |||
125 | static int prepare_processes(void) | 115 | static int prepare_processes(void) |
126 | { | 116 | { |
127 | int error; | 117 | int error; |
128 | 118 | ||
129 | pm_prepare_console(); | 119 | pm_prepare_console(); |
130 | |||
131 | sys_sync(); | 120 | sys_sync(); |
132 | |||
133 | disable_nonboot_cpus(); | 121 | disable_nonboot_cpus(); |
134 | 122 | ||
135 | if (freeze_processes()) { | 123 | if (freeze_processes()) { |
@@ -162,15 +150,6 @@ static void unprepare_processes(void) | |||
162 | pm_restore_console(); | 150 | pm_restore_console(); |
163 | } | 151 | } |
164 | 152 | ||
165 | static int prepare_devices(void) | ||
166 | { | ||
167 | int error; | ||
168 | |||
169 | if ((error = device_suspend(PMSG_FREEZE))) | ||
170 | printk("Some devices failed to suspend\n"); | ||
171 | return error; | ||
172 | } | ||
173 | |||
174 | /** | 153 | /** |
175 | * pm_suspend_disk - The granpappy of power management. | 154 | * pm_suspend_disk - The granpappy of power management. |
176 | * | 155 | * |
@@ -187,17 +166,14 @@ int pm_suspend_disk(void) | |||
187 | error = prepare_processes(); | 166 | error = prepare_processes(); |
188 | if (error) | 167 | if (error) |
189 | return error; | 168 | return error; |
190 | error = prepare_devices(); | ||
191 | 169 | ||
170 | error = device_suspend(PMSG_FREEZE); | ||
192 | if (error) { | 171 | if (error) { |
172 | printk("Some devices failed to suspend\n"); | ||
193 | unprepare_processes(); | 173 | unprepare_processes(); |
194 | return error; | 174 | return error; |
195 | } | 175 | } |
196 | 176 | ||
197 | pr_debug("PM: Attempting to suspend to disk.\n"); | ||
198 | if (pm_disk_mode == PM_DISK_FIRMWARE) | ||
199 | return pm_ops->enter(PM_SUSPEND_DISK); | ||
200 | |||
201 | pr_debug("PM: snapshotting memory.\n"); | 177 | pr_debug("PM: snapshotting memory.\n"); |
202 | in_suspend = 1; | 178 | in_suspend = 1; |
203 | if ((error = swsusp_suspend())) | 179 | if ((error = swsusp_suspend())) |
@@ -208,11 +184,20 @@ int pm_suspend_disk(void) | |||
208 | error = swsusp_write(); | 184 | error = swsusp_write(); |
209 | if (!error) | 185 | if (!error) |
210 | power_down(pm_disk_mode); | 186 | power_down(pm_disk_mode); |
187 | else { | ||
188 | /* swsusp_write can not fail in device_resume, | ||
189 | no need to do second device_resume */ | ||
190 | swsusp_free(); | ||
191 | unprepare_processes(); | ||
192 | return error; | ||
193 | } | ||
211 | } else | 194 | } else |
212 | pr_debug("PM: Image restored successfully.\n"); | 195 | pr_debug("PM: Image restored successfully.\n"); |
196 | |||
213 | swsusp_free(); | 197 | swsusp_free(); |
214 | Done: | 198 | Done: |
215 | finish(); | 199 | device_resume(); |
200 | unprepare_processes(); | ||
216 | return error; | 201 | return error; |
217 | } | 202 | } |
218 | 203 | ||
@@ -233,9 +218,12 @@ static int software_resume(void) | |||
233 | { | 218 | { |
234 | int error; | 219 | int error; |
235 | 220 | ||
221 | down(&pm_sem); | ||
236 | if (!swsusp_resume_device) { | 222 | if (!swsusp_resume_device) { |
237 | if (!strlen(resume_file)) | 223 | if (!strlen(resume_file)) { |
224 | up(&pm_sem); | ||
238 | return -ENOENT; | 225 | return -ENOENT; |
226 | } | ||
239 | swsusp_resume_device = name_to_dev_t(resume_file); | 227 | swsusp_resume_device = name_to_dev_t(resume_file); |
240 | pr_debug("swsusp: Resume From Partition %s\n", resume_file); | 228 | pr_debug("swsusp: Resume From Partition %s\n", resume_file); |
241 | } else { | 229 | } else { |
@@ -248,6 +236,7 @@ static int software_resume(void) | |||
248 | * FIXME: If noresume is specified, we need to find the partition | 236 | * FIXME: If noresume is specified, we need to find the partition |
249 | * and reset it back to normal swap space. | 237 | * and reset it back to normal swap space. |
250 | */ | 238 | */ |
239 | up(&pm_sem); | ||
251 | return 0; | 240 | return 0; |
252 | } | 241 | } |
253 | 242 | ||
@@ -270,20 +259,24 @@ static int software_resume(void) | |||
270 | 259 | ||
271 | pr_debug("PM: Preparing devices for restore.\n"); | 260 | pr_debug("PM: Preparing devices for restore.\n"); |
272 | 261 | ||
273 | if ((error = prepare_devices())) | 262 | if ((error = device_suspend(PMSG_FREEZE))) { |
263 | printk("Some devices failed to suspend\n"); | ||
274 | goto Free; | 264 | goto Free; |
265 | } | ||
275 | 266 | ||
276 | mb(); | 267 | mb(); |
277 | 268 | ||
278 | pr_debug("PM: Restoring saved image.\n"); | 269 | pr_debug("PM: Restoring saved image.\n"); |
279 | swsusp_resume(); | 270 | swsusp_resume(); |
280 | pr_debug("PM: Restore failed, recovering.n"); | 271 | pr_debug("PM: Restore failed, recovering.n"); |
281 | finish(); | 272 | device_resume(); |
282 | Free: | 273 | Free: |
283 | swsusp_free(); | 274 | swsusp_free(); |
284 | Cleanup: | 275 | Cleanup: |
285 | unprepare_processes(); | 276 | unprepare_processes(); |
286 | Done: | 277 | Done: |
278 | /* For success case, the suspend path will release the lock */ | ||
279 | up(&pm_sem); | ||
287 | pr_debug("PM: Resume from disk failed.\n"); | 280 | pr_debug("PM: Resume from disk failed.\n"); |
288 | return 0; | 281 | return 0; |
289 | } | 282 | } |
@@ -390,7 +383,9 @@ static ssize_t resume_store(struct subsystem * subsys, const char * buf, size_t | |||
390 | if (sscanf(buf, "%u:%u", &maj, &min) == 2) { | 383 | if (sscanf(buf, "%u:%u", &maj, &min) == 2) { |
391 | res = MKDEV(maj,min); | 384 | res = MKDEV(maj,min); |
392 | if (maj == MAJOR(res) && min == MINOR(res)) { | 385 | if (maj == MAJOR(res) && min == MINOR(res)) { |
386 | down(&pm_sem); | ||
393 | swsusp_resume_device = res; | 387 | swsusp_resume_device = res; |
388 | up(&pm_sem); | ||
394 | printk("Attempting manual resume\n"); | 389 | printk("Attempting manual resume\n"); |
395 | noresume = 0; | 390 | noresume = 0; |
396 | software_resume(); | 391 | software_resume(); |
diff --git a/kernel/power/main.c b/kernel/power/main.c index 71aa0fd22007..22bdc93cc038 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c | |||
@@ -143,11 +143,12 @@ static void suspend_finish(suspend_state_t state) | |||
143 | 143 | ||
144 | 144 | ||
145 | 145 | ||
146 | static char * pm_states[] = { | 146 | static char *pm_states[PM_SUSPEND_MAX] = { |
147 | [PM_SUSPEND_STANDBY] = "standby", | 147 | [PM_SUSPEND_STANDBY] = "standby", |
148 | [PM_SUSPEND_MEM] = "mem", | 148 | [PM_SUSPEND_MEM] = "mem", |
149 | #ifdef CONFIG_SOFTWARE_SUSPEND | ||
149 | [PM_SUSPEND_DISK] = "disk", | 150 | [PM_SUSPEND_DISK] = "disk", |
150 | NULL, | 151 | #endif |
151 | }; | 152 | }; |
152 | 153 | ||
153 | 154 | ||
diff --git a/kernel/power/pm.c b/kernel/power/pm.c index 61deda04e39e..159149321b3c 100644 --- a/kernel/power/pm.c +++ b/kernel/power/pm.c | |||
@@ -60,9 +60,8 @@ struct pm_dev *pm_register(pm_dev_t type, | |||
60 | unsigned long id, | 60 | unsigned long id, |
61 | pm_callback callback) | 61 | pm_callback callback) |
62 | { | 62 | { |
63 | struct pm_dev *dev = kmalloc(sizeof(struct pm_dev), GFP_KERNEL); | 63 | struct pm_dev *dev = kzalloc(sizeof(struct pm_dev), GFP_KERNEL); |
64 | if (dev) { | 64 | if (dev) { |
65 | memset(dev, 0, sizeof(*dev)); | ||
66 | dev->type = type; | 65 | dev->type = type; |
67 | dev->id = id; | 66 | dev->id = id; |
68 | dev->callback = callback; | 67 | dev->callback = callback; |
diff --git a/kernel/power/process.c b/kernel/power/process.c index 3bd0d261818f..28de118f7a0b 100644 --- a/kernel/power/process.c +++ b/kernel/power/process.c | |||
@@ -38,7 +38,6 @@ void refrigerator(void) | |||
38 | processes around? */ | 38 | processes around? */ |
39 | long save; | 39 | long save; |
40 | save = current->state; | 40 | save = current->state; |
41 | current->state = TASK_UNINTERRUPTIBLE; | ||
42 | pr_debug("%s entered refrigerator\n", current->comm); | 41 | pr_debug("%s entered refrigerator\n", current->comm); |
43 | printk("="); | 42 | printk("="); |
44 | 43 | ||
@@ -47,8 +46,10 @@ void refrigerator(void) | |||
47 | recalc_sigpending(); /* We sent fake signal, clean it up */ | 46 | recalc_sigpending(); /* We sent fake signal, clean it up */ |
48 | spin_unlock_irq(¤t->sighand->siglock); | 47 | spin_unlock_irq(¤t->sighand->siglock); |
49 | 48 | ||
50 | while (frozen(current)) | 49 | while (frozen(current)) { |
50 | current->state = TASK_UNINTERRUPTIBLE; | ||
51 | schedule(); | 51 | schedule(); |
52 | } | ||
52 | pr_debug("%s left refrigerator\n", current->comm); | 53 | pr_debug("%s left refrigerator\n", current->comm); |
53 | current->state = save; | 54 | current->state = save; |
54 | } | 55 | } |
@@ -80,13 +81,33 @@ int freeze_processes(void) | |||
80 | } while_each_thread(g, p); | 81 | } while_each_thread(g, p); |
81 | read_unlock(&tasklist_lock); | 82 | read_unlock(&tasklist_lock); |
82 | yield(); /* Yield is okay here */ | 83 | yield(); /* Yield is okay here */ |
83 | if (time_after(jiffies, start_time + TIMEOUT)) { | 84 | if (todo && time_after(jiffies, start_time + TIMEOUT)) { |
84 | printk( "\n" ); | 85 | printk( "\n" ); |
85 | printk(KERN_ERR " stopping tasks failed (%d tasks remaining)\n", todo ); | 86 | printk(KERN_ERR " stopping tasks failed (%d tasks remaining)\n", todo ); |
86 | return todo; | 87 | break; |
87 | } | 88 | } |
88 | } while(todo); | 89 | } while(todo); |
89 | 90 | ||
91 | /* This does not unfreeze processes that are already frozen | ||
92 | * (we have slightly ugly calling convention in that respect, | ||
93 | * and caller must call thaw_processes() if something fails), | ||
94 | * but it cleans up leftover PF_FREEZE requests. | ||
95 | */ | ||
96 | if (todo) { | ||
97 | read_lock(&tasklist_lock); | ||
98 | do_each_thread(g, p) | ||
99 | if (freezing(p)) { | ||
100 | pr_debug(" clean up: %s\n", p->comm); | ||
101 | p->flags &= ~PF_FREEZE; | ||
102 | spin_lock_irqsave(&p->sighand->siglock, flags); | ||
103 | recalc_sigpending_tsk(p); | ||
104 | spin_unlock_irqrestore(&p->sighand->siglock, flags); | ||
105 | } | ||
106 | while_each_thread(g, p); | ||
107 | read_unlock(&tasklist_lock); | ||
108 | return todo; | ||
109 | } | ||
110 | |||
90 | printk( "|\n" ); | 111 | printk( "|\n" ); |
91 | BUG_ON(in_atomic()); | 112 | BUG_ON(in_atomic()); |
92 | return 0; | 113 | return 0; |
diff --git a/kernel/power/swsusp.c b/kernel/power/swsusp.c index f2bc71b9fe8b..d967e875ee82 100644 --- a/kernel/power/swsusp.c +++ b/kernel/power/swsusp.c | |||
@@ -31,6 +31,9 @@ | |||
31 | * Alex Badea <vampire@go.ro>: | 31 | * Alex Badea <vampire@go.ro>: |
32 | * Fixed runaway init | 32 | * Fixed runaway init |
33 | * | 33 | * |
34 | * Andreas Steinmetz <ast@domdv.de>: | ||
35 | * Added encrypted suspend option | ||
36 | * | ||
34 | * More state savers are welcome. Especially for the scsi layer... | 37 | * More state savers are welcome. Especially for the scsi layer... |
35 | * | 38 | * |
36 | * For TODOs,FIXMEs also look in Documentation/power/swsusp.txt | 39 | * For TODOs,FIXMEs also look in Documentation/power/swsusp.txt |
@@ -71,8 +74,16 @@ | |||
71 | #include <asm/tlbflush.h> | 74 | #include <asm/tlbflush.h> |
72 | #include <asm/io.h> | 75 | #include <asm/io.h> |
73 | 76 | ||
77 | #include <linux/random.h> | ||
78 | #include <linux/crypto.h> | ||
79 | #include <asm/scatterlist.h> | ||
80 | |||
74 | #include "power.h" | 81 | #include "power.h" |
75 | 82 | ||
83 | #define CIPHER "aes" | ||
84 | #define MAXKEY 32 | ||
85 | #define MAXIV 32 | ||
86 | |||
76 | /* References to section boundaries */ | 87 | /* References to section boundaries */ |
77 | extern const void __nosave_begin, __nosave_end; | 88 | extern const void __nosave_begin, __nosave_end; |
78 | 89 | ||
@@ -103,7 +114,8 @@ static suspend_pagedir_t *pagedir_save; | |||
103 | #define SWSUSP_SIG "S1SUSPEND" | 114 | #define SWSUSP_SIG "S1SUSPEND" |
104 | 115 | ||
105 | static struct swsusp_header { | 116 | static struct swsusp_header { |
106 | char reserved[PAGE_SIZE - 20 - sizeof(swp_entry_t)]; | 117 | char reserved[PAGE_SIZE - 20 - MAXKEY - MAXIV - sizeof(swp_entry_t)]; |
118 | u8 key_iv[MAXKEY+MAXIV]; | ||
107 | swp_entry_t swsusp_info; | 119 | swp_entry_t swsusp_info; |
108 | char orig_sig[10]; | 120 | char orig_sig[10]; |
109 | char sig[10]; | 121 | char sig[10]; |
@@ -129,6 +141,131 @@ static struct swsusp_info swsusp_info; | |||
129 | static unsigned short swapfile_used[MAX_SWAPFILES]; | 141 | static unsigned short swapfile_used[MAX_SWAPFILES]; |
130 | static unsigned short root_swap; | 142 | static unsigned short root_swap; |
131 | 143 | ||
144 | static int write_page(unsigned long addr, swp_entry_t * loc); | ||
145 | static int bio_read_page(pgoff_t page_off, void * page); | ||
146 | |||
147 | static u8 key_iv[MAXKEY+MAXIV]; | ||
148 | |||
149 | #ifdef CONFIG_SWSUSP_ENCRYPT | ||
150 | |||
151 | static int crypto_init(int mode, void **mem) | ||
152 | { | ||
153 | int error = 0; | ||
154 | int len; | ||
155 | char *modemsg; | ||
156 | struct crypto_tfm *tfm; | ||
157 | |||
158 | modemsg = mode ? "suspend not possible" : "resume not possible"; | ||
159 | |||
160 | tfm = crypto_alloc_tfm(CIPHER, CRYPTO_TFM_MODE_CBC); | ||
161 | if(!tfm) { | ||
162 | printk(KERN_ERR "swsusp: no tfm, %s\n", modemsg); | ||
163 | error = -EINVAL; | ||
164 | goto out; | ||
165 | } | ||
166 | |||
167 | if(MAXKEY < crypto_tfm_alg_min_keysize(tfm)) { | ||
168 | printk(KERN_ERR "swsusp: key buffer too small, %s\n", modemsg); | ||
169 | error = -ENOKEY; | ||
170 | goto fail; | ||
171 | } | ||
172 | |||
173 | if (mode) | ||
174 | get_random_bytes(key_iv, MAXKEY+MAXIV); | ||
175 | |||
176 | len = crypto_tfm_alg_max_keysize(tfm); | ||
177 | if (len > MAXKEY) | ||
178 | len = MAXKEY; | ||
179 | |||
180 | if (crypto_cipher_setkey(tfm, key_iv, len)) { | ||
181 | printk(KERN_ERR "swsusp: key setup failure, %s\n", modemsg); | ||
182 | error = -EKEYREJECTED; | ||
183 | goto fail; | ||
184 | } | ||
185 | |||
186 | len = crypto_tfm_alg_ivsize(tfm); | ||
187 | |||
188 | if (MAXIV < len) { | ||
189 | printk(KERN_ERR "swsusp: iv buffer too small, %s\n", modemsg); | ||
190 | error = -EOVERFLOW; | ||
191 | goto fail; | ||
192 | } | ||
193 | |||
194 | crypto_cipher_set_iv(tfm, key_iv+MAXKEY, len); | ||
195 | |||
196 | *mem=(void *)tfm; | ||
197 | |||
198 | goto out; | ||
199 | |||
200 | fail: crypto_free_tfm(tfm); | ||
201 | out: return error; | ||
202 | } | ||
203 | |||
204 | static __inline__ void crypto_exit(void *mem) | ||
205 | { | ||
206 | crypto_free_tfm((struct crypto_tfm *)mem); | ||
207 | } | ||
208 | |||
209 | static __inline__ int crypto_write(struct pbe *p, void *mem) | ||
210 | { | ||
211 | int error = 0; | ||
212 | struct scatterlist src, dst; | ||
213 | |||
214 | src.page = virt_to_page(p->address); | ||
215 | src.offset = 0; | ||
216 | src.length = PAGE_SIZE; | ||
217 | dst.page = virt_to_page((void *)&swsusp_header); | ||
218 | dst.offset = 0; | ||
219 | dst.length = PAGE_SIZE; | ||
220 | |||
221 | error = crypto_cipher_encrypt((struct crypto_tfm *)mem, &dst, &src, | ||
222 | PAGE_SIZE); | ||
223 | |||
224 | if (!error) | ||
225 | error = write_page((unsigned long)&swsusp_header, | ||
226 | &(p->swap_address)); | ||
227 | return error; | ||
228 | } | ||
229 | |||
230 | static __inline__ int crypto_read(struct pbe *p, void *mem) | ||
231 | { | ||
232 | int error = 0; | ||
233 | struct scatterlist src, dst; | ||
234 | |||
235 | error = bio_read_page(swp_offset(p->swap_address), (void *)p->address); | ||
236 | if (!error) { | ||
237 | src.offset = 0; | ||
238 | src.length = PAGE_SIZE; | ||
239 | dst.offset = 0; | ||
240 | dst.length = PAGE_SIZE; | ||
241 | src.page = dst.page = virt_to_page((void *)p->address); | ||
242 | |||
243 | error = crypto_cipher_decrypt((struct crypto_tfm *)mem, &dst, | ||
244 | &src, PAGE_SIZE); | ||
245 | } | ||
246 | return error; | ||
247 | } | ||
248 | #else | ||
249 | static __inline__ int crypto_init(int mode, void *mem) | ||
250 | { | ||
251 | return 0; | ||
252 | } | ||
253 | |||
254 | static __inline__ void crypto_exit(void *mem) | ||
255 | { | ||
256 | } | ||
257 | |||
258 | static __inline__ int crypto_write(struct pbe *p, void *mem) | ||
259 | { | ||
260 | return write_page(p->address, &(p->swap_address)); | ||
261 | } | ||
262 | |||
263 | static __inline__ int crypto_read(struct pbe *p, void *mem) | ||
264 | { | ||
265 | return bio_read_page(swp_offset(p->swap_address), (void *)p->address); | ||
266 | } | ||
267 | #endif | ||
268 | |||
132 | static int mark_swapfiles(swp_entry_t prev) | 269 | static int mark_swapfiles(swp_entry_t prev) |
133 | { | 270 | { |
134 | int error; | 271 | int error; |
@@ -140,6 +277,7 @@ static int mark_swapfiles(swp_entry_t prev) | |||
140 | !memcmp("SWAPSPACE2",swsusp_header.sig, 10)) { | 277 | !memcmp("SWAPSPACE2",swsusp_header.sig, 10)) { |
141 | memcpy(swsusp_header.orig_sig,swsusp_header.sig, 10); | 278 | memcpy(swsusp_header.orig_sig,swsusp_header.sig, 10); |
142 | memcpy(swsusp_header.sig,SWSUSP_SIG, 10); | 279 | memcpy(swsusp_header.sig,SWSUSP_SIG, 10); |
280 | memcpy(swsusp_header.key_iv, key_iv, MAXKEY+MAXIV); | ||
143 | swsusp_header.swsusp_info = prev; | 281 | swsusp_header.swsusp_info = prev; |
144 | error = rw_swap_page_sync(WRITE, | 282 | error = rw_swap_page_sync(WRITE, |
145 | swp_entry(root_swap, 0), | 283 | swp_entry(root_swap, 0), |
@@ -179,9 +317,9 @@ static int swsusp_swap_check(void) /* This is called before saving image */ | |||
179 | len=strlen(resume_file); | 317 | len=strlen(resume_file); |
180 | root_swap = 0xFFFF; | 318 | root_swap = 0xFFFF; |
181 | 319 | ||
182 | swap_list_lock(); | 320 | spin_lock(&swap_lock); |
183 | for (i=0; i<MAX_SWAPFILES; i++) { | 321 | for (i=0; i<MAX_SWAPFILES; i++) { |
184 | if (swap_info[i].flags == 0) { | 322 | if (!(swap_info[i].flags & SWP_WRITEOK)) { |
185 | swapfile_used[i]=SWAPFILE_UNUSED; | 323 | swapfile_used[i]=SWAPFILE_UNUSED; |
186 | } else { | 324 | } else { |
187 | if (!len) { | 325 | if (!len) { |
@@ -202,7 +340,7 @@ static int swsusp_swap_check(void) /* This is called before saving image */ | |||
202 | } | 340 | } |
203 | } | 341 | } |
204 | } | 342 | } |
205 | swap_list_unlock(); | 343 | spin_unlock(&swap_lock); |
206 | return (root_swap != 0xffff) ? 0 : -ENODEV; | 344 | return (root_swap != 0xffff) ? 0 : -ENODEV; |
207 | } | 345 | } |
208 | 346 | ||
@@ -216,12 +354,12 @@ static void lock_swapdevices(void) | |||
216 | { | 354 | { |
217 | int i; | 355 | int i; |
218 | 356 | ||
219 | swap_list_lock(); | 357 | spin_lock(&swap_lock); |
220 | for (i = 0; i< MAX_SWAPFILES; i++) | 358 | for (i = 0; i< MAX_SWAPFILES; i++) |
221 | if (swapfile_used[i] == SWAPFILE_IGNORED) { | 359 | if (swapfile_used[i] == SWAPFILE_IGNORED) { |
222 | swap_info[i].flags ^= 0xFF; | 360 | swap_info[i].flags ^= SWP_WRITEOK; |
223 | } | 361 | } |
224 | swap_list_unlock(); | 362 | spin_unlock(&swap_lock); |
225 | } | 363 | } |
226 | 364 | ||
227 | /** | 365 | /** |
@@ -286,6 +424,10 @@ static int data_write(void) | |||
286 | int error = 0, i = 0; | 424 | int error = 0, i = 0; |
287 | unsigned int mod = nr_copy_pages / 100; | 425 | unsigned int mod = nr_copy_pages / 100; |
288 | struct pbe *p; | 426 | struct pbe *p; |
427 | void *tfm; | ||
428 | |||
429 | if ((error = crypto_init(1, &tfm))) | ||
430 | return error; | ||
289 | 431 | ||
290 | if (!mod) | 432 | if (!mod) |
291 | mod = 1; | 433 | mod = 1; |
@@ -294,11 +436,14 @@ static int data_write(void) | |||
294 | for_each_pbe (p, pagedir_nosave) { | 436 | for_each_pbe (p, pagedir_nosave) { |
295 | if (!(i%mod)) | 437 | if (!(i%mod)) |
296 | printk( "\b\b\b\b%3d%%", i / mod ); | 438 | printk( "\b\b\b\b%3d%%", i / mod ); |
297 | if ((error = write_page(p->address, &(p->swap_address)))) | 439 | if ((error = crypto_write(p, tfm))) { |
440 | crypto_exit(tfm); | ||
298 | return error; | 441 | return error; |
442 | } | ||
299 | i++; | 443 | i++; |
300 | } | 444 | } |
301 | printk("\b\b\b\bdone\n"); | 445 | printk("\b\b\b\bdone\n"); |
446 | crypto_exit(tfm); | ||
302 | return error; | 447 | return error; |
303 | } | 448 | } |
304 | 449 | ||
@@ -385,7 +530,6 @@ static int write_pagedir(void) | |||
385 | * write_suspend_image - Write entire image and metadata. | 530 | * write_suspend_image - Write entire image and metadata. |
386 | * | 531 | * |
387 | */ | 532 | */ |
388 | |||
389 | static int write_suspend_image(void) | 533 | static int write_suspend_image(void) |
390 | { | 534 | { |
391 | int error; | 535 | int error; |
@@ -400,6 +544,7 @@ static int write_suspend_image(void) | |||
400 | if ((error = close_swap())) | 544 | if ((error = close_swap())) |
401 | goto FreePagedir; | 545 | goto FreePagedir; |
402 | Done: | 546 | Done: |
547 | memset(key_iv, 0, MAXKEY+MAXIV); | ||
403 | return error; | 548 | return error; |
404 | FreePagedir: | 549 | FreePagedir: |
405 | free_pagedir_entries(); | 550 | free_pagedir_entries(); |
@@ -591,18 +736,7 @@ static void copy_data_pages(void) | |||
591 | 736 | ||
592 | static int calc_nr(int nr_copy) | 737 | static int calc_nr(int nr_copy) |
593 | { | 738 | { |
594 | int extra = 0; | 739 | return nr_copy + (nr_copy+PBES_PER_PAGE-2)/(PBES_PER_PAGE-1); |
595 | int mod = !!(nr_copy % PBES_PER_PAGE); | ||
596 | int diff = (nr_copy / PBES_PER_PAGE) + mod; | ||
597 | |||
598 | do { | ||
599 | extra += diff; | ||
600 | nr_copy += diff; | ||
601 | mod = !!(nr_copy % PBES_PER_PAGE); | ||
602 | diff = (nr_copy / PBES_PER_PAGE) + mod - extra; | ||
603 | } while (diff > 0); | ||
604 | |||
605 | return nr_copy; | ||
606 | } | 740 | } |
607 | 741 | ||
608 | /** | 742 | /** |
@@ -886,20 +1020,21 @@ int swsusp_suspend(void) | |||
886 | * at resume time, and evil weirdness ensues. | 1020 | * at resume time, and evil weirdness ensues. |
887 | */ | 1021 | */ |
888 | if ((error = device_power_down(PMSG_FREEZE))) { | 1022 | if ((error = device_power_down(PMSG_FREEZE))) { |
1023 | printk(KERN_ERR "Some devices failed to power down, aborting suspend\n"); | ||
889 | local_irq_enable(); | 1024 | local_irq_enable(); |
890 | return error; | 1025 | return error; |
891 | } | 1026 | } |
892 | 1027 | ||
893 | if ((error = swsusp_swap_check())) { | 1028 | if ((error = swsusp_swap_check())) { |
894 | printk(KERN_ERR "swsusp: FATAL: cannot find swap device, try " | 1029 | printk(KERN_ERR "swsusp: cannot find swap device, try swapon -a.\n"); |
895 | "swapon -a!\n"); | 1030 | device_power_up(); |
896 | local_irq_enable(); | 1031 | local_irq_enable(); |
897 | return error; | 1032 | return error; |
898 | } | 1033 | } |
899 | 1034 | ||
900 | save_processor_state(); | 1035 | save_processor_state(); |
901 | if ((error = swsusp_arch_suspend())) | 1036 | if ((error = swsusp_arch_suspend())) |
902 | printk("Error %d suspending\n", error); | 1037 | printk(KERN_ERR "Error %d suspending\n", error); |
903 | /* Restore control flow magically appears here */ | 1038 | /* Restore control flow magically appears here */ |
904 | restore_processor_state(); | 1039 | restore_processor_state(); |
905 | BUG_ON (nr_copy_pages_check != nr_copy_pages); | 1040 | BUG_ON (nr_copy_pages_check != nr_copy_pages); |
@@ -924,6 +1059,7 @@ int swsusp_resume(void) | |||
924 | BUG_ON(!error); | 1059 | BUG_ON(!error); |
925 | restore_processor_state(); | 1060 | restore_processor_state(); |
926 | restore_highmem(); | 1061 | restore_highmem(); |
1062 | touch_softlockup_watchdog(); | ||
927 | device_power_up(); | 1063 | device_power_up(); |
928 | local_irq_enable(); | 1064 | local_irq_enable(); |
929 | return error; | 1065 | return error; |
@@ -1179,7 +1315,8 @@ static const char * sanity_check(void) | |||
1179 | if (strcmp(swsusp_info.uts.machine,system_utsname.machine)) | 1315 | if (strcmp(swsusp_info.uts.machine,system_utsname.machine)) |
1180 | return "machine"; | 1316 | return "machine"; |
1181 | #if 0 | 1317 | #if 0 |
1182 | if(swsusp_info.cpus != num_online_cpus()) | 1318 | /* We can't use number of online CPUs when we use hotplug to remove them ;-))) */ |
1319 | if (swsusp_info.cpus != num_possible_cpus()) | ||
1183 | return "number of cpus"; | 1320 | return "number of cpus"; |
1184 | #endif | 1321 | #endif |
1185 | return NULL; | 1322 | return NULL; |
@@ -1212,13 +1349,14 @@ static int check_sig(void) | |||
1212 | return error; | 1349 | return error; |
1213 | if (!memcmp(SWSUSP_SIG, swsusp_header.sig, 10)) { | 1350 | if (!memcmp(SWSUSP_SIG, swsusp_header.sig, 10)) { |
1214 | memcpy(swsusp_header.sig, swsusp_header.orig_sig, 10); | 1351 | memcpy(swsusp_header.sig, swsusp_header.orig_sig, 10); |
1352 | memcpy(key_iv, swsusp_header.key_iv, MAXKEY+MAXIV); | ||
1353 | memset(swsusp_header.key_iv, 0, MAXKEY+MAXIV); | ||
1215 | 1354 | ||
1216 | /* | 1355 | /* |
1217 | * Reset swap signature now. | 1356 | * Reset swap signature now. |
1218 | */ | 1357 | */ |
1219 | error = bio_write_page(0, &swsusp_header); | 1358 | error = bio_write_page(0, &swsusp_header); |
1220 | } else { | 1359 | } else { |
1221 | printk(KERN_ERR "swsusp: Suspend partition has wrong signature?\n"); | ||
1222 | return -EINVAL; | 1360 | return -EINVAL; |
1223 | } | 1361 | } |
1224 | if (!error) | 1362 | if (!error) |
@@ -1239,6 +1377,10 @@ static int data_read(struct pbe *pblist) | |||
1239 | int error = 0; | 1377 | int error = 0; |
1240 | int i = 0; | 1378 | int i = 0; |
1241 | int mod = swsusp_info.image_pages / 100; | 1379 | int mod = swsusp_info.image_pages / 100; |
1380 | void *tfm; | ||
1381 | |||
1382 | if ((error = crypto_init(0, &tfm))) | ||
1383 | return error; | ||
1242 | 1384 | ||
1243 | if (!mod) | 1385 | if (!mod) |
1244 | mod = 1; | 1386 | mod = 1; |
@@ -1250,14 +1392,15 @@ static int data_read(struct pbe *pblist) | |||
1250 | if (!(i % mod)) | 1392 | if (!(i % mod)) |
1251 | printk("\b\b\b\b%3d%%", i / mod); | 1393 | printk("\b\b\b\b%3d%%", i / mod); |
1252 | 1394 | ||
1253 | error = bio_read_page(swp_offset(p->swap_address), | 1395 | if ((error = crypto_read(p, tfm))) { |
1254 | (void *)p->address); | 1396 | crypto_exit(tfm); |
1255 | if (error) | ||
1256 | return error; | 1397 | return error; |
1398 | } | ||
1257 | 1399 | ||
1258 | i++; | 1400 | i++; |
1259 | } | 1401 | } |
1260 | printk("\b\b\b\bdone\n"); | 1402 | printk("\b\b\b\bdone\n"); |
1403 | crypto_exit(tfm); | ||
1261 | return error; | 1404 | return error; |
1262 | } | 1405 | } |
1263 | 1406 | ||
@@ -1385,6 +1528,7 @@ int swsusp_read(void) | |||
1385 | 1528 | ||
1386 | error = read_suspend_image(); | 1529 | error = read_suspend_image(); |
1387 | blkdev_put(resume_bdev); | 1530 | blkdev_put(resume_bdev); |
1531 | memset(key_iv, 0, MAXKEY+MAXIV); | ||
1388 | 1532 | ||
1389 | if (!error) | 1533 | if (!error) |
1390 | pr_debug("swsusp: Reading resume file was successful\n"); | 1534 | pr_debug("swsusp: Reading resume file was successful\n"); |