aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/suspend.h6
-rw-r--r--kernel/power/disk.c8
-rw-r--r--kernel/power/power.h13
-rw-r--r--kernel/power/snapshot.c14
-rw-r--r--kernel/power/swsusp.c558
5 files changed, 418 insertions, 181 deletions
diff --git a/include/linux/suspend.h b/include/linux/suspend.h
index a61c04f804b2..33bbaea23aaf 100644
--- a/include/linux/suspend.h
+++ b/include/linux/suspend.h
@@ -14,11 +14,7 @@
14typedef struct pbe { 14typedef struct pbe {
15 unsigned long address; /* address of the copy */ 15 unsigned long address; /* address of the copy */
16 unsigned long orig_address; /* original address of page */ 16 unsigned long orig_address; /* original address of page */
17 swp_entry_t swap_address; 17 struct pbe *next;
18
19 struct pbe *next; /* also used as scratch space at
20 * end of page (see link, diskpage)
21 */
22} suspend_pagedir_t; 18} suspend_pagedir_t;
23 19
24#define for_each_pbe(pbe, pblist) \ 20#define for_each_pbe(pbe, pblist) \
diff --git a/kernel/power/disk.c b/kernel/power/disk.c
index 4d944b281b28..76a5131b0e80 100644
--- a/kernel/power/disk.c
+++ b/kernel/power/disk.c
@@ -25,9 +25,9 @@
25extern suspend_disk_method_t pm_disk_mode; 25extern suspend_disk_method_t pm_disk_mode;
26 26
27extern int swsusp_suspend(void); 27extern int swsusp_suspend(void);
28extern int swsusp_write(void); 28extern int swsusp_write(struct pbe *pblist, unsigned int nr_pages);
29extern int swsusp_check(void); 29extern int swsusp_check(void);
30extern int swsusp_read(void); 30extern int swsusp_read(struct pbe **pblist_ptr);
31extern void swsusp_close(void); 31extern void swsusp_close(void);
32extern int swsusp_resume(void); 32extern int swsusp_resume(void);
33 33
@@ -176,7 +176,7 @@ int pm_suspend_disk(void)
176 if (in_suspend) { 176 if (in_suspend) {
177 device_resume(); 177 device_resume();
178 pr_debug("PM: writing image.\n"); 178 pr_debug("PM: writing image.\n");
179 error = swsusp_write(); 179 error = swsusp_write(pagedir_nosave, nr_copy_pages);
180 if (!error) 180 if (!error)
181 power_down(pm_disk_mode); 181 power_down(pm_disk_mode);
182 else { 182 else {
@@ -247,7 +247,7 @@ static int software_resume(void)
247 247
248 pr_debug("PM: Reading swsusp image.\n"); 248 pr_debug("PM: Reading swsusp image.\n");
249 249
250 if ((error = swsusp_read())) { 250 if ((error = swsusp_read(&pagedir_nosave))) {
251 swsusp_free(); 251 swsusp_free();
252 goto Thaw; 252 goto Thaw;
253 } 253 }
diff --git a/kernel/power/power.h b/kernel/power/power.h
index 6c042b5ee14b..977877c6dcfc 100644
--- a/kernel/power/power.h
+++ b/kernel/power/power.h
@@ -9,19 +9,14 @@
9#define SUSPEND_CONSOLE (MAX_NR_CONSOLES-1) 9#define SUSPEND_CONSOLE (MAX_NR_CONSOLES-1)
10#endif 10#endif
11 11
12#define MAX_PBES ((PAGE_SIZE - sizeof(struct new_utsname) \
13 - 4 - 3*sizeof(unsigned long) - sizeof(int) \
14 - sizeof(void *)) / sizeof(swp_entry_t))
15
16struct swsusp_info { 12struct swsusp_info {
17 struct new_utsname uts; 13 struct new_utsname uts;
18 u32 version_code; 14 u32 version_code;
19 unsigned long num_physpages; 15 unsigned long num_physpages;
20 int cpus; 16 int cpus;
21 unsigned long image_pages; 17 unsigned long image_pages;
22 unsigned long pagedir_pages; 18 unsigned long pages;
23 suspend_pagedir_t * suspend_pagedir; 19 swp_entry_t start;
24 swp_entry_t pagedir[MAX_PBES];
25} __attribute__((aligned(PAGE_SIZE))); 20} __attribute__((aligned(PAGE_SIZE)));
26 21
27 22
@@ -67,6 +62,8 @@ extern asmlinkage int swsusp_arch_resume(void);
67 62
68extern void free_pagedir(struct pbe *pblist); 63extern void free_pagedir(struct pbe *pblist);
69extern struct pbe *alloc_pagedir(unsigned nr_pages, gfp_t gfp_mask, int safe_needed); 64extern struct pbe *alloc_pagedir(unsigned nr_pages, gfp_t gfp_mask, int safe_needed);
70extern void create_pbe_list(struct pbe *pblist, unsigned nr_pages);
71extern void swsusp_free(void); 65extern void swsusp_free(void);
72extern int alloc_data_pages(struct pbe *pblist, gfp_t gfp_mask, int safe_needed); 66extern int alloc_data_pages(struct pbe *pblist, gfp_t gfp_mask, int safe_needed);
67extern unsigned int snapshot_nr_pages(void);
68extern struct pbe *snapshot_pblist(void);
69extern void snapshot_pblist_set(struct pbe *pblist);
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c
index 4a6dbcefd378..152d56cdf017 100644
--- a/kernel/power/snapshot.c
+++ b/kernel/power/snapshot.c
@@ -33,6 +33,9 @@
33 33
34#include "power.h" 34#include "power.h"
35 35
36struct pbe *pagedir_nosave;
37unsigned int nr_copy_pages;
38
36#ifdef CONFIG_HIGHMEM 39#ifdef CONFIG_HIGHMEM
37struct highmem_page { 40struct highmem_page {
38 char *data; 41 char *data;
@@ -244,7 +247,7 @@ static inline void fill_pb_page(struct pbe *pbpage)
244 * of memory pages allocated with alloc_pagedir() 247 * of memory pages allocated with alloc_pagedir()
245 */ 248 */
246 249
247void create_pbe_list(struct pbe *pblist, unsigned int nr_pages) 250static inline void create_pbe_list(struct pbe *pblist, unsigned int nr_pages)
248{ 251{
249 struct pbe *pbpage, *p; 252 struct pbe *pbpage, *p;
250 unsigned int num = PBES_PER_PAGE; 253 unsigned int num = PBES_PER_PAGE;
@@ -261,7 +264,6 @@ void create_pbe_list(struct pbe *pblist, unsigned int nr_pages)
261 p->next = p + 1; 264 p->next = p + 1;
262 p->next = NULL; 265 p->next = NULL;
263 } 266 }
264 pr_debug("create_pbe_list(): initialized %d PBEs\n", num);
265} 267}
266 268
267/** 269/**
@@ -332,7 +334,8 @@ struct pbe *alloc_pagedir(unsigned int nr_pages, gfp_t gfp_mask, int safe_needed
332 if (!pbe) { /* get_zeroed_page() failed */ 334 if (!pbe) { /* get_zeroed_page() failed */
333 free_pagedir(pblist); 335 free_pagedir(pblist);
334 pblist = NULL; 336 pblist = NULL;
335 } 337 } else
338 create_pbe_list(pblist, nr_pages);
336 return pblist; 339 return pblist;
337} 340}
338 341
@@ -395,7 +398,6 @@ static struct pbe *swsusp_alloc(unsigned int nr_pages)
395 printk(KERN_ERR "suspend: Allocating pagedir failed.\n"); 398 printk(KERN_ERR "suspend: Allocating pagedir failed.\n");
396 return NULL; 399 return NULL;
397 } 400 }
398 create_pbe_list(pblist, nr_pages);
399 401
400 if (alloc_data_pages(pblist, GFP_ATOMIC | __GFP_COLD, 0)) { 402 if (alloc_data_pages(pblist, GFP_ATOMIC | __GFP_COLD, 0)) {
401 printk(KERN_ERR "suspend: Allocating image pages failed.\n"); 403 printk(KERN_ERR "suspend: Allocating image pages failed.\n");
@@ -421,10 +423,6 @@ asmlinkage int swsusp_save(void)
421 (nr_pages + PBES_PER_PAGE - 1) / PBES_PER_PAGE, 423 (nr_pages + PBES_PER_PAGE - 1) / PBES_PER_PAGE,
422 PAGES_FOR_IO, nr_free_pages()); 424 PAGES_FOR_IO, nr_free_pages());
423 425
424 /* This is needed because of the fixed size of swsusp_info */
425 if (MAX_PBES < (nr_pages + PBES_PER_PAGE - 1) / PBES_PER_PAGE)
426 return -ENOSPC;
427
428 if (!enough_free_mem(nr_pages)) { 426 if (!enough_free_mem(nr_pages)) {
429 printk(KERN_ERR "swsusp: Not enough free memory\n"); 427 printk(KERN_ERR "swsusp: Not enough free memory\n");
430 return -ENOMEM; 428 return -ENOMEM;
diff --git a/kernel/power/swsusp.c b/kernel/power/swsusp.c
index bd3097c583bf..b09bd7c0998d 100644
--- a/kernel/power/swsusp.c
+++ b/kernel/power/swsusp.c
@@ -30,6 +30,9 @@
30 * Alex Badea <vampire@go.ro>: 30 * Alex Badea <vampire@go.ro>:
31 * Fixed runaway init 31 * Fixed runaway init
32 * 32 *
33 * Rafael J. Wysocki <rjw@sisk.pl>
34 * Added the swap map data structure and reworked the handling of swap
35 *
33 * More state savers are welcome. Especially for the scsi layer... 36 * More state savers are welcome. Especially for the scsi layer...
34 * 37 *
35 * For TODOs,FIXMEs also look in Documentation/power/swsusp.txt 38 * For TODOs,FIXMEs also look in Documentation/power/swsusp.txt
@@ -76,18 +79,6 @@ static int restore_highmem(void) { return 0; }
76 79
77extern char resume_file[]; 80extern char resume_file[];
78 81
79/* Local variables that should not be affected by save */
80unsigned int nr_copy_pages __nosavedata = 0;
81
82/* Suspend pagedir is allocated before final copy, therefore it
83 must be freed after resume
84
85 Warning: this is even more evil than it seems. Pagedirs this file
86 talks about are completely different from page directories used by
87 MMU hardware.
88 */
89suspend_pagedir_t *pagedir_nosave __nosavedata = NULL;
90
91#define SWSUSP_SIG "S1SUSPEND" 82#define SWSUSP_SIG "S1SUSPEND"
92 83
93static struct swsusp_header { 84static struct swsusp_header {
@@ -238,48 +229,205 @@ static int write_page(unsigned long addr, swp_entry_t *loc)
238} 229}
239 230
240/** 231/**
241 * data_free - Free the swap entries used by the saved image. 232 * Swap map-handling functions
233 *
234 * The swap map is a data structure used for keeping track of each page
235 * written to the swap. It consists of many swap_map_page structures
236 * that contain each an array of MAP_PAGE_SIZE swap entries.
237 * These structures are linked together with the help of either the
238 * .next (in memory) or the .next_swap (in swap) member.
242 * 239 *
243 * Walk the list of used swap entries and free each one. 240 * The swap map is created during suspend. At that time we need to keep
244 * This is only used for cleanup when suspend fails. 241 * it in memory, because we have to free all of the allocated swap
242 * entries if an error occurs. The memory needed is preallocated
243 * so that we know in advance if there's enough of it.
244 *
245 * The first swap_map_page structure is filled with the swap entries that
246 * correspond to the first MAP_PAGE_SIZE data pages written to swap and
247 * so on. After the all of the data pages have been written, the order
248 * of the swap_map_page structures in the map is reversed so that they
249 * can be read from swap in the original order. This causes the data
250 * pages to be loaded in exactly the same order in which they have been
251 * saved.
252 *
253 * During resume we only need to use one swap_map_page structure
254 * at a time, which means that we only need to use two memory pages for
255 * reading the image - one for reading the swap_map_page structures
256 * and the second for reading the data pages from swap.
245 */ 257 */
246static void data_free(void) 258
259#define MAP_PAGE_SIZE ((PAGE_SIZE - sizeof(swp_entry_t) - sizeof(void *)) \
260 / sizeof(swp_entry_t))
261
262struct swap_map_page {
263 swp_entry_t entries[MAP_PAGE_SIZE];
264 swp_entry_t next_swap;
265 struct swap_map_page *next;
266};
267
268static inline void free_swap_map(struct swap_map_page *swap_map)
247{ 269{
248 swp_entry_t entry; 270 struct swap_map_page *swp;
249 struct pbe *p;
250 271
251 for_each_pbe (p, pagedir_nosave) { 272 while (swap_map) {
252 entry = p->swap_address; 273 swp = swap_map->next;
253 if (entry.val) 274 free_page((unsigned long)swap_map);
254 swap_free(entry); 275 swap_map = swp;
255 else 276 }
256 break; 277}
278
279static struct swap_map_page *alloc_swap_map(unsigned int nr_pages)
280{
281 struct swap_map_page *swap_map, *swp;
282 unsigned n = 0;
283
284 if (!nr_pages)
285 return NULL;
286
287 pr_debug("alloc_swap_map(): nr_pages = %d\n", nr_pages);
288 swap_map = (struct swap_map_page *)get_zeroed_page(GFP_ATOMIC);
289 swp = swap_map;
290 for (n = MAP_PAGE_SIZE; n < nr_pages; n += MAP_PAGE_SIZE) {
291 swp->next = (struct swap_map_page *)get_zeroed_page(GFP_ATOMIC);
292 swp = swp->next;
293 if (!swp) {
294 free_swap_map(swap_map);
295 return NULL;
296 }
257 } 297 }
298 return swap_map;
258} 299}
259 300
260/** 301/**
261 * data_write - Write saved image to swap. 302 * reverse_swap_map - reverse the order of pages in the swap map
262 * 303 * @swap_map
263 * Walk the list of pages in the image and sync each one to swap.
264 */ 304 */
265static int data_write(void) 305
306static inline struct swap_map_page *reverse_swap_map(struct swap_map_page *swap_map)
266{ 307{
267 int error = 0, i = 0; 308 struct swap_map_page *prev, *next;
268 unsigned int mod = nr_copy_pages / 100; 309
269 struct pbe *p; 310 prev = NULL;
311 while (swap_map) {
312 next = swap_map->next;
313 swap_map->next = prev;
314 prev = swap_map;
315 swap_map = next;
316 }
317 return prev;
318}
270 319
271 if (!mod) 320/**
272 mod = 1; 321 * free_swap_map_entries - free the swap entries allocated to store
322 * the swap map @swap_map (this is only called in case of an error)
323 */
324static inline void free_swap_map_entries(struct swap_map_page *swap_map)
325{
326 while (swap_map) {
327 if (swap_map->next_swap.val)
328 swap_free(swap_map->next_swap);
329 swap_map = swap_map->next;
330 }
331}
273 332
274 printk( "Writing data to swap (%d pages)... ", nr_copy_pages ); 333/**
275 for_each_pbe (p, pagedir_nosave) { 334 * save_swap_map - save the swap map used for tracing the data pages
276 if (!(i%mod)) 335 * stored in the swap
277 printk( "\b\b\b\b%3d%%", i / mod ); 336 */
278 if ((error = write_page(p->address, &p->swap_address))) 337
338static int save_swap_map(struct swap_map_page *swap_map, swp_entry_t *start)
339{
340 swp_entry_t entry = (swp_entry_t){0};
341 int error;
342
343 while (swap_map) {
344 swap_map->next_swap = entry;
345 if ((error = write_page((unsigned long)swap_map, &entry)))
279 return error; 346 return error;
280 i++; 347 swap_map = swap_map->next;
281 } 348 }
282 printk("\b\b\b\bdone\n"); 349 *start = entry;
350 return 0;
351}
352
353/**
354 * free_image_entries - free the swap entries allocated to store
355 * the image data pages (this is only called in case of an error)
356 */
357
358static inline void free_image_entries(struct swap_map_page *swp)
359{
360 unsigned k;
361
362 while (swp) {
363 for (k = 0; k < MAP_PAGE_SIZE; k++)
364 if (swp->entries[k].val)
365 swap_free(swp->entries[k]);
366 swp = swp->next;
367 }
368}
369
370/**
371 * The swap_map_handle structure is used for handling the swap map in
372 * a file-alike way
373 */
374
375struct swap_map_handle {
376 struct swap_map_page *cur;
377 unsigned int k;
378};
379
380static inline void init_swap_map_handle(struct swap_map_handle *handle,
381 struct swap_map_page *map)
382{
383 handle->cur = map;
384 handle->k = 0;
385}
386
387static inline int swap_map_write_page(struct swap_map_handle *handle,
388 unsigned long addr)
389{
390 int error;
391
392 error = write_page(addr, handle->cur->entries + handle->k);
393 if (error)
394 return error;
395 if (++handle->k >= MAP_PAGE_SIZE) {
396 handle->cur = handle->cur->next;
397 handle->k = 0;
398 }
399 return 0;
400}
401
402/**
403 * save_image_data - save the data pages pointed to by the PBEs
404 * from the list @pblist using the swap map handle @handle
405 * (assume there are @nr_pages data pages to save)
406 */
407
408static int save_image_data(struct pbe *pblist,
409 struct swap_map_handle *handle,
410 unsigned int nr_pages)
411{
412 unsigned int m;
413 struct pbe *p;
414 int error = 0;
415
416 printk("Saving image data pages (%u pages) ... ", nr_pages);
417 m = nr_pages / 100;
418 if (!m)
419 m = 1;
420 nr_pages = 0;
421 for_each_pbe (p, pblist) {
422 error = swap_map_write_page(handle, p->address);
423 if (error)
424 break;
425 if (!(nr_pages % m))
426 printk("\b\b\b\b%3d%%", nr_pages / m);
427 nr_pages++;
428 }
429 if (!error)
430 printk("\b\b\b\bdone\n");
283 return error; 431 return error;
284} 432}
285 433
@@ -295,19 +443,20 @@ static void dump_info(void)
295 pr_debug(" swsusp: UTS Domain: %s\n",swsusp_info.uts.domainname); 443 pr_debug(" swsusp: UTS Domain: %s\n",swsusp_info.uts.domainname);
296 pr_debug(" swsusp: CPUs: %d\n",swsusp_info.cpus); 444 pr_debug(" swsusp: CPUs: %d\n",swsusp_info.cpus);
297 pr_debug(" swsusp: Image: %ld Pages\n",swsusp_info.image_pages); 445 pr_debug(" swsusp: Image: %ld Pages\n",swsusp_info.image_pages);
298 pr_debug(" swsusp: Pagedir: %ld Pages\n",swsusp_info.pagedir_pages); 446 pr_debug(" swsusp: Total: %ld Pages\n", swsusp_info.pages);
299} 447}
300 448
301static void init_header(void) 449static void init_header(unsigned int nr_pages)
302{ 450{
303 memset(&swsusp_info, 0, sizeof(swsusp_info)); 451 memset(&swsusp_info, 0, sizeof(swsusp_info));
304 swsusp_info.version_code = LINUX_VERSION_CODE; 452 swsusp_info.version_code = LINUX_VERSION_CODE;
305 swsusp_info.num_physpages = num_physpages; 453 swsusp_info.num_physpages = num_physpages;
306 memcpy(&swsusp_info.uts, &system_utsname, sizeof(system_utsname)); 454 memcpy(&swsusp_info.uts, &system_utsname, sizeof(system_utsname));
307 455
308 swsusp_info.suspend_pagedir = pagedir_nosave;
309 swsusp_info.cpus = num_online_cpus(); 456 swsusp_info.cpus = num_online_cpus();
310 swsusp_info.image_pages = nr_copy_pages; 457 swsusp_info.image_pages = nr_pages;
458 swsusp_info.pages = nr_pages +
459 ((nr_pages * sizeof(long) + PAGE_SIZE - 1) >> PAGE_SHIFT);
311} 460}
312 461
313static int close_swap(void) 462static int close_swap(void)
@@ -326,39 +475,53 @@ static int close_swap(void)
326} 475}
327 476
328/** 477/**
329 * free_pagedir_entries - Free pages used by the page directory. 478 * pack_orig_addresses - the .orig_address fields of the PBEs from the
330 * 479 * list starting at @pbe are stored in the array @buf[] (1 page)
331 * This is used during suspend for error recovery.
332 */ 480 */
333 481
334static void free_pagedir_entries(void) 482static inline struct pbe *pack_orig_addresses(unsigned long *buf,
483 struct pbe *pbe)
335{ 484{
336 int i; 485 int j;
337 486
338 for (i = 0; i < swsusp_info.pagedir_pages; i++) 487 for (j = 0; j < PAGE_SIZE / sizeof(long) && pbe; j++) {
339 swap_free(swsusp_info.pagedir[i]); 488 buf[j] = pbe->orig_address;
489 pbe = pbe->next;
490 }
491 if (!pbe)
492 for (; j < PAGE_SIZE / sizeof(long); j++)
493 buf[j] = 0;
494 return pbe;
340} 495}
341 496
342
343/** 497/**
344 * write_pagedir - Write the array of pages holding the page directory. 498 * save_image_metadata - save the .orig_address fields of the PBEs
345 * @last: Last swap entry we write (needed for header). 499 * from the list @pblist using the swap map handle @handle
346 */ 500 */
347 501
348static int write_pagedir(void) 502static int save_image_metadata(struct pbe *pblist,
503 struct swap_map_handle *handle)
349{ 504{
350 int error = 0; 505 unsigned long *buf;
351 unsigned int n = 0; 506 unsigned int n = 0;
352 struct pbe *pbe; 507 struct pbe *p;
508 int error = 0;
353 509
354 printk( "Writing pagedir..."); 510 printk("Saving image metadata ... ");
355 for_each_pb_page (pbe, pagedir_nosave) { 511 buf = (unsigned long *)get_zeroed_page(GFP_ATOMIC);
356 if ((error = write_page((unsigned long)pbe, &swsusp_info.pagedir[n++]))) 512 if (!buf)
357 return error; 513 return -ENOMEM;
514 p = pblist;
515 while (p) {
516 p = pack_orig_addresses(buf, p);
517 error = swap_map_write_page(handle, (unsigned long)buf);
518 if (error)
519 break;
520 n++;
358 } 521 }
359 522 free_page((unsigned long)buf);
360 swsusp_info.pagedir_pages = n; 523 if (!error)
361 printk("done (%u pages)\n", n); 524 printk("done (%u pages saved)\n", n);
362 return error; 525 return error;
363} 526}
364 527
@@ -384,33 +547,48 @@ static int enough_swap(unsigned int nr_pages)
384 547
385/** 548/**
386 * write_suspend_image - Write entire image and metadata. 549 * write_suspend_image - Write entire image and metadata.
387 *
388 */ 550 */
389static int write_suspend_image(void) 551static int write_suspend_image(struct pbe *pblist, unsigned int nr_pages)
390{ 552{
553 struct swap_map_page *swap_map;
554 struct swap_map_handle handle;
391 int error; 555 int error;
392 556
393 if (!enough_swap(nr_copy_pages)) { 557 if (!enough_swap(nr_pages)) {
394 printk(KERN_ERR "swsusp: Not enough free swap\n"); 558 printk(KERN_ERR "swsusp: Not enough free swap\n");
395 return -ENOSPC; 559 return -ENOSPC;
396 } 560 }
397 561
398 init_header(); 562 init_header(nr_pages);
399 if ((error = data_write())) 563 swap_map = alloc_swap_map(swsusp_info.pages);
400 goto FreeData; 564 if (!swap_map)
565 return -ENOMEM;
566 init_swap_map_handle(&handle, swap_map);
401 567
402 if ((error = write_pagedir())) 568 error = save_image_metadata(pblist, &handle);
403 goto FreePagedir; 569 if (!error)
570 error = save_image_data(pblist, &handle, nr_pages);
571 if (error)
572 goto Free_image_entries;
404 573
405 if ((error = close_swap())) 574 swap_map = reverse_swap_map(swap_map);
406 goto FreePagedir; 575 error = save_swap_map(swap_map, &swsusp_info.start);
407 Done: 576 if (error)
577 goto Free_map_entries;
578
579 error = close_swap();
580 if (error)
581 goto Free_map_entries;
582
583Free_swap_map:
584 free_swap_map(swap_map);
408 return error; 585 return error;
409 FreePagedir: 586
410 free_pagedir_entries(); 587Free_map_entries:
411 FreeData: 588 free_swap_map_entries(swap_map);
412 data_free(); 589Free_image_entries:
413 goto Done; 590 free_image_entries(swap_map);
591 goto Free_swap_map;
414} 592}
415 593
416/* It is important _NOT_ to umount filesystems at this point. We want 594/* It is important _NOT_ to umount filesystems at this point. We want
@@ -418,7 +596,7 @@ static int write_suspend_image(void)
418 * filesystem clean: it is not. (And it does not matter, if we resume 596 * filesystem clean: it is not. (And it does not matter, if we resume
419 * correctly, we'll mark system clean, anyway.) 597 * correctly, we'll mark system clean, anyway.)
420 */ 598 */
421int swsusp_write(void) 599int swsusp_write(struct pbe *pblist, unsigned int nr_pages)
422{ 600{
423 int error; 601 int error;
424 602
@@ -427,14 +605,12 @@ int swsusp_write(void)
427 return error; 605 return error;
428 } 606 }
429 lock_swapdevices(); 607 lock_swapdevices();
430 error = write_suspend_image(); 608 error = write_suspend_image(pblist, nr_pages);
431 /* This will unlock ignored swap devices since writing is finished */ 609 /* This will unlock ignored swap devices since writing is finished */
432 lock_swapdevices(); 610 lock_swapdevices();
433 return error; 611 return error;
434} 612}
435 613
436
437
438int swsusp_suspend(void) 614int swsusp_suspend(void)
439{ 615{
440 int error; 616 int error;
@@ -531,7 +707,6 @@ static void copy_page_backup_list(struct pbe *dst, struct pbe *src)
531 /* We assume both lists contain the same number of elements */ 707 /* We assume both lists contain the same number of elements */
532 while (src) { 708 while (src) {
533 dst->orig_address = src->orig_address; 709 dst->orig_address = src->orig_address;
534 dst->swap_address = src->swap_address;
535 dst = dst->next; 710 dst = dst->next;
536 src = src->next; 711 src = src->next;
537 } 712 }
@@ -611,6 +786,61 @@ static int bio_write_page(pgoff_t page_off, void *page)
611 return submit(WRITE, page_off, page); 786 return submit(WRITE, page_off, page);
612} 787}
613 788
789/**
790 * The following functions allow us to read data using a swap map
791 * in a file-alike way
792 */
793
794static inline void release_swap_map_reader(struct swap_map_handle *handle)
795{
796 if (handle->cur)
797 free_page((unsigned long)handle->cur);
798 handle->cur = NULL;
799}
800
801static inline int get_swap_map_reader(struct swap_map_handle *handle,
802 swp_entry_t start)
803{
804 int error;
805
806 if (!swp_offset(start))
807 return -EINVAL;
808 handle->cur = (struct swap_map_page *)get_zeroed_page(GFP_ATOMIC);
809 if (!handle->cur)
810 return -ENOMEM;
811 error = bio_read_page(swp_offset(start), handle->cur);
812 if (error) {
813 release_swap_map_reader(handle);
814 return error;
815 }
816 handle->k = 0;
817 return 0;
818}
819
820static inline int swap_map_read_page(struct swap_map_handle *handle, void *buf)
821{
822 unsigned long offset;
823 int error;
824
825 if (!handle->cur)
826 return -EINVAL;
827 offset = swp_offset(handle->cur->entries[handle->k]);
828 if (!offset)
829 return -EINVAL;
830 error = bio_read_page(offset, buf);
831 if (error)
832 return error;
833 if (++handle->k >= MAP_PAGE_SIZE) {
834 handle->k = 0;
835 offset = swp_offset(handle->cur->next_swap);
836 if (!offset)
837 release_swap_map_reader(handle);
838 else
839 error = bio_read_page(offset, handle->cur);
840 }
841 return error;
842}
843
614/* 844/*
615 * Sanity check if this image makes sense with this kernel/swap context 845 * Sanity check if this image makes sense with this kernel/swap context
616 * I really don't think that it's foolproof but more than nothing.. 846 * I really don't think that it's foolproof but more than nothing..
@@ -639,7 +869,6 @@ static const char *sanity_check(void)
639 return NULL; 869 return NULL;
640} 870}
641 871
642
643static int check_header(void) 872static int check_header(void)
644{ 873{
645 const char *reason = NULL; 874 const char *reason = NULL;
@@ -653,7 +882,6 @@ static int check_header(void)
653 printk(KERN_ERR "swsusp: Resume mismatch: %s\n",reason); 882 printk(KERN_ERR "swsusp: Resume mismatch: %s\n",reason);
654 return -EPERM; 883 return -EPERM;
655 } 884 }
656 nr_copy_pages = swsusp_info.image_pages;
657 return error; 885 return error;
658} 886}
659 887
@@ -680,75 +908,88 @@ static int check_sig(void)
680} 908}
681 909
682/** 910/**
683 * data_read - Read image pages from swap. 911 * load_image_data - load the image data using the swap map handle
684 * 912 * @handle and store them using the page backup list @pblist
685 * You do not need to check for overlaps, check_pagedir() 913 * (assume there are @nr_pages pages to load)
686 * already did that.
687 */ 914 */
688 915
689static int data_read(struct pbe *pblist) 916static int load_image_data(struct pbe *pblist,
917 struct swap_map_handle *handle,
918 unsigned int nr_pages)
690{ 919{
920 int error;
921 unsigned int m;
691 struct pbe *p; 922 struct pbe *p;
692 int error = 0;
693 int i = 0;
694 int mod = swsusp_info.image_pages / 100;
695
696 if (!mod)
697 mod = 1;
698
699 printk("swsusp: Reading image data (%lu pages): ",
700 swsusp_info.image_pages);
701
702 for_each_pbe (p, pblist) {
703 if (!(i % mod))
704 printk("\b\b\b\b%3d%%", i / mod);
705 923
706 if ((error = bio_read_page(swp_offset(p->swap_address), 924 if (!pblist)
707 (void *)p->address))) 925 return -EINVAL;
708 return error; 926 printk("Loading image data pages (%u pages) ... ", nr_pages);
709 927 m = nr_pages / 100;
710 i++; 928 if (!m)
929 m = 1;
930 nr_pages = 0;
931 p = pblist;
932 while (p) {
933 error = swap_map_read_page(handle, (void *)p->address);
934 if (error)
935 break;
936 p = p->next;
937 if (!(nr_pages % m))
938 printk("\b\b\b\b%3d%%", nr_pages / m);
939 nr_pages++;
711 } 940 }
712 printk("\b\b\b\bdone\n"); 941 if (!error)
942 printk("\b\b\b\bdone\n");
713 return error; 943 return error;
714} 944}
715 945
716/** 946/**
717 * read_pagedir - Read page backup list pages from swap 947 * unpack_orig_addresses - copy the elements of @buf[] (1 page) to
948 * the PBEs in the list starting at @pbe
718 */ 949 */
719 950
720static int read_pagedir(struct pbe *pblist) 951static inline struct pbe *unpack_orig_addresses(unsigned long *buf,
952 struct pbe *pbe)
721{ 953{
722 struct pbe *pbpage, *p; 954 int j;
723 unsigned int i = 0;
724 int error;
725 955
726 if (!pblist) 956 for (j = 0; j < PAGE_SIZE / sizeof(long) && pbe; j++) {
727 return -EFAULT; 957 pbe->orig_address = buf[j];
958 pbe = pbe->next;
959 }
960 return pbe;
961}
728 962
729 printk("swsusp: Reading pagedir (%lu pages)\n", 963/**
730 swsusp_info.pagedir_pages); 964 * load_image_metadata - load the image metadata using the swap map
965 * handle @handle and put them into the PBEs in the list @pblist
966 */
731 967
732 for_each_pb_page (pbpage, pblist) { 968static int load_image_metadata(struct pbe *pblist, struct swap_map_handle *handle)
733 unsigned long offset = swp_offset(swsusp_info.pagedir[i++]); 969{
970 struct pbe *p;
971 unsigned long *buf;
972 unsigned int n = 0;
973 int error = 0;
734 974
735 error = -EFAULT; 975 printk("Loading image metadata ... ");
736 if (offset) { 976 buf = (unsigned long *)get_zeroed_page(GFP_ATOMIC);
737 p = (pbpage + PB_PAGE_SKIP)->next; 977 if (!buf)
738 error = bio_read_page(offset, (void *)pbpage); 978 return -ENOMEM;
739 (pbpage + PB_PAGE_SKIP)->next = p; 979 p = pblist;
740 } 980 while (p) {
981 error = swap_map_read_page(handle, buf);
741 if (error) 982 if (error)
742 break; 983 break;
984 p = unpack_orig_addresses(buf, p);
985 n++;
743 } 986 }
744 987 free_page((unsigned long)buf);
745 if (!error) 988 if (!error)
746 BUG_ON(i != swsusp_info.pagedir_pages); 989 printk("done (%u pages loaded)\n", n);
747
748 return error; 990 return error;
749} 991}
750 992
751
752static int check_suspend_image(void) 993static int check_suspend_image(void)
753{ 994{
754 int error = 0; 995 int error = 0;
@@ -762,34 +1003,39 @@ static int check_suspend_image(void)
762 return 0; 1003 return 0;
763} 1004}
764 1005
765static int read_suspend_image(void) 1006static int read_suspend_image(struct pbe **pblist_ptr)
766{ 1007{
767 int error = 0; 1008 int error = 0;
768 struct pbe *p; 1009 struct pbe *p, *pblist;
1010 struct swap_map_handle handle;
1011 unsigned int nr_pages = swsusp_info.image_pages;
769 1012
770 if (!(p = alloc_pagedir(nr_copy_pages, GFP_ATOMIC, 0))) 1013 p = alloc_pagedir(nr_pages, GFP_ATOMIC, 0);
1014 if (!p)
771 return -ENOMEM; 1015 return -ENOMEM;
772 1016 error = get_swap_map_reader(&handle, swsusp_info.start);
773 if ((error = read_pagedir(p))) 1017 if (error)
1018 /* The PBE list at p will be released by swsusp_free() */
774 return error; 1019 return error;
775 create_pbe_list(p, nr_copy_pages); 1020 error = load_image_metadata(p, &handle);
776 mark_unsafe_pages(p); 1021 if (!error) {
777 pagedir_nosave = alloc_pagedir(nr_copy_pages, GFP_ATOMIC, 1); 1022 mark_unsafe_pages(p);
778 if (pagedir_nosave) { 1023 pblist = alloc_pagedir(nr_pages, GFP_ATOMIC, 1);
779 create_pbe_list(pagedir_nosave, nr_copy_pages); 1024 if (pblist)
780 copy_page_backup_list(pagedir_nosave, p); 1025 copy_page_backup_list(pblist, p);
1026 free_pagedir(p);
1027 if (!pblist)
1028 error = -ENOMEM;
1029
1030 /* Allocate memory for the image and read the data from swap */
1031 if (!error)
1032 error = alloc_data_pages(pblist, GFP_ATOMIC, 1);
1033 if (!error)
1034 error = load_image_data(pblist, &handle, nr_pages);
1035 if (!error)
1036 *pblist_ptr = pblist;
781 } 1037 }
782 free_pagedir(p); 1038 release_swap_map_reader(&handle);
783 if (!pagedir_nosave)
784 return -ENOMEM;
785
786 /* Allocate memory for the image and read the data from swap */
787
788 error = alloc_data_pages(pagedir_nosave, GFP_ATOMIC, 1);
789
790 if (!error)
791 error = data_read(pagedir_nosave);
792
793 return error; 1039 return error;
794} 1040}
795 1041
@@ -821,7 +1067,7 @@ int swsusp_check(void)
821 * swsusp_read - Read saved image from swap. 1067 * swsusp_read - Read saved image from swap.
822 */ 1068 */
823 1069
824int swsusp_read(void) 1070int swsusp_read(struct pbe **pblist_ptr)
825{ 1071{
826 int error; 1072 int error;
827 1073
@@ -830,7 +1076,7 @@ int swsusp_read(void)
830 return PTR_ERR(resume_bdev); 1076 return PTR_ERR(resume_bdev);
831 } 1077 }
832 1078
833 error = read_suspend_image(); 1079 error = read_suspend_image(pblist_ptr);
834 blkdev_put(resume_bdev); 1080 blkdev_put(resume_bdev);
835 1081
836 if (!error) 1082 if (!error)