aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2006-01-06 03:13:05 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2006-01-06 11:33:40 -0500
commit7088a5c00103ef48782d6c359cd12b13a10666e6 (patch)
treeb731c8af48e00c0ec88bbe57b6b2a2c1ec20fbde /kernel
parentf2d97f02961e8b1f8a24befb88ab0e5c886586ff (diff)
[PATCH] swsusp: introduce the swap map structure
This patch introduces the swap map structure that can be used by swsusp for keeping tracks of data pages written to the swap.  The structure itself is described in a comment within the patch. The overall idea is to reduce the amount of metadata written to the swap and to write and read the image pages sequentially, in a file-alike way. This makes the swap-handling part of swsusp fairly independent of its snapshot-handling part and will hopefully allow us to completely separate these two parts in the future. This patch is needed to remove the suspend image size limit imposed by the limited size of the swsusp_info structure, which is essential for x86-64 systems with more than 512 MB of RAM. Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Acked-by: Pavel Machek <pavel@suse.cz> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'kernel')
-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
4 files changed, 417 insertions, 176 deletions
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)