blob: f77f9397a36455def5df2969d2efd4b2dd2d389e [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/kernel/power/swsusp.c
3 *
Pavel Machek96bc7ae2005-10-30 14:59:58 -08004 * This file provides code to write suspend image to swap and read it back.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 *
6 * Copyright (C) 1998-2001 Gabor Kuti <seasons@fornax.hu>
Rafael J. Wysocki25761b62005-10-30 14:59:56 -08007 * Copyright (C) 1998,2001-2005 Pavel Machek <pavel@suse.cz>
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 *
9 * This file is released under the GPLv2.
10 *
11 * I'd like to thank the following people for their work:
Pavel Machek2e4d5822005-06-25 14:55:12 -070012 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070013 * 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 *
Pavel Machek2e4d5822005-06-25 14:55:12 -070017 * Steve Doddi <dirk@loth.demon.co.uk>:
Linus Torvalds1da177e2005-04-16 15:20:36 -070018 * 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 *
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -080033 * Rafael J. Wysocki <rjw@sisk.pl>
34 * Added the swap map data structure and reworked the handling of swap
35 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070036 * 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/module.h>
42#include <linux/mm.h>
43#include <linux/suspend.h>
44#include <linux/smp_lock.h>
45#include <linux/file.h>
46#include <linux/utsname.h>
47#include <linux/version.h>
48#include <linux/delay.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070049#include <linux/bitops.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070050#include <linux/spinlock.h>
51#include <linux/genhd.h>
52#include <linux/kernel.h>
53#include <linux/major.h>
54#include <linux/swap.h>
55#include <linux/pm.h>
56#include <linux/device.h>
57#include <linux/buffer_head.h>
58#include <linux/swapops.h>
59#include <linux/bootmem.h>
60#include <linux/syscalls.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070061#include <linux/highmem.h>
62#include <linux/bio.h>
63
64#include <asm/uaccess.h>
65#include <asm/mmu_context.h>
66#include <asm/pgtable.h>
67#include <asm/tlbflush.h>
68#include <asm/io.h>
69
70#include "power.h"
71
Rafael J. Wysocki0fbeb5a2005-11-08 21:34:41 -080072#ifdef CONFIG_HIGHMEM
Rafael J. Wysocki72a97e02006-01-06 00:13:46 -080073unsigned int count_highmem_pages(void);
Rafael J. Wysocki0fbeb5a2005-11-08 21:34:41 -080074int save_highmem(void);
75int restore_highmem(void);
76#else
77static int save_highmem(void) { return 0; }
78static int restore_highmem(void) { return 0; }
Rafael J. Wysocki72a97e02006-01-06 00:13:46 -080079static unsigned int count_highmem_pages(void) { return 0; }
Rafael J. Wysocki0fbeb5a2005-11-08 21:34:41 -080080#endif
81
Linus Torvalds1da177e2005-04-16 15:20:36 -070082extern char resume_file[];
83
Linus Torvalds1da177e2005-04-16 15:20:36 -070084#define SWSUSP_SIG "S1SUSPEND"
85
86static struct swsusp_header {
Rafael J. Wysockif2d97f02006-01-06 00:12:24 -080087 char reserved[PAGE_SIZE - 20 - sizeof(swp_entry_t)];
Linus Torvalds1da177e2005-04-16 15:20:36 -070088 swp_entry_t swsusp_info;
89 char orig_sig[10];
90 char sig[10];
91} __attribute__((packed, aligned(PAGE_SIZE))) swsusp_header;
92
93static struct swsusp_info swsusp_info;
94
95/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070096 * Saving part...
97 */
98
99/* We memorize in swapfile_used what swap devices are used for suspension */
100#define SWAPFILE_UNUSED 0
101#define SWAPFILE_SUSPEND 1 /* This is the suspending device */
102#define SWAPFILE_IGNORED 2 /* Those are other swap devices ignored for suspension */
103
104static unsigned short swapfile_used[MAX_SWAPFILES];
105static unsigned short root_swap;
106
107static int mark_swapfiles(swp_entry_t prev)
108{
109 int error;
110
Pavel Machek2e4d5822005-06-25 14:55:12 -0700111 rw_swap_page_sync(READ,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112 swp_entry(root_swap, 0),
113 virt_to_page((unsigned long)&swsusp_header));
114 if (!memcmp("SWAP-SPACE",swsusp_header.sig, 10) ||
115 !memcmp("SWAPSPACE2",swsusp_header.sig, 10)) {
116 memcpy(swsusp_header.orig_sig,swsusp_header.sig, 10);
117 memcpy(swsusp_header.sig,SWSUSP_SIG, 10);
118 swsusp_header.swsusp_info = prev;
Pavel Machek2e4d5822005-06-25 14:55:12 -0700119 error = rw_swap_page_sync(WRITE,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120 swp_entry(root_swap, 0),
121 virt_to_page((unsigned long)
122 &swsusp_header));
123 } else {
124 pr_debug("swsusp: Partition is not swap space.\n");
125 error = -ENODEV;
126 }
127 return error;
128}
129
130/*
131 * Check whether the swap device is the specified resume
132 * device, irrespective of whether they are specified by
133 * identical names.
134 *
135 * (Thus, device inode aliasing is allowed. You can say /dev/hda4
136 * instead of /dev/ide/host0/bus0/target0/lun0/part4 [if using devfs]
137 * and they'll be considered the same device. This is *necessary* for
138 * devfs, since the resume code can only recognize the form /dev/hda4,
139 * but the suspend code would see the long name.)
140 */
141static int is_resume_device(const struct swap_info_struct *swap_info)
142{
143 struct file *file = swap_info->swap_file;
144 struct inode *inode = file->f_dentry->d_inode;
145
146 return S_ISBLK(inode->i_mode) &&
147 swsusp_resume_device == MKDEV(imajor(inode), iminor(inode));
148}
149
150static int swsusp_swap_check(void) /* This is called before saving image */
151{
152 int i, len;
Pavel Machek2e4d5822005-06-25 14:55:12 -0700153
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 len=strlen(resume_file);
155 root_swap = 0xFFFF;
Pavel Machek2e4d5822005-06-25 14:55:12 -0700156
Hugh Dickinsdae06ac2005-09-03 15:54:42 -0700157 spin_lock(&swap_lock);
Pavel Machek2e4d5822005-06-25 14:55:12 -0700158 for (i=0; i<MAX_SWAPFILES; i++) {
Hugh Dickinsdae06ac2005-09-03 15:54:42 -0700159 if (!(swap_info[i].flags & SWP_WRITEOK)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160 swapfile_used[i]=SWAPFILE_UNUSED;
161 } else {
Pavel Machek2e4d5822005-06-25 14:55:12 -0700162 if (!len) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163 printk(KERN_WARNING "resume= option should be used to set suspend device" );
Pavel Machek2e4d5822005-06-25 14:55:12 -0700164 if (root_swap == 0xFFFF) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 swapfile_used[i] = SWAPFILE_SUSPEND;
166 root_swap = i;
167 } else
Pavel Machek2e4d5822005-06-25 14:55:12 -0700168 swapfile_used[i] = SWAPFILE_IGNORED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169 } else {
170 /* we ignore all swap devices that are not the resume_file */
171 if (is_resume_device(&swap_info[i])) {
172 swapfile_used[i] = SWAPFILE_SUSPEND;
173 root_swap = i;
174 } else {
175 swapfile_used[i] = SWAPFILE_IGNORED;
176 }
177 }
178 }
179 }
Hugh Dickinsdae06ac2005-09-03 15:54:42 -0700180 spin_unlock(&swap_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181 return (root_swap != 0xffff) ? 0 : -ENODEV;
182}
183
184/**
185 * This is called after saving image so modification
186 * will be lost after resume... and that's what we want.
187 * we make the device unusable. A new call to
Pavel Machek2e4d5822005-06-25 14:55:12 -0700188 * lock_swapdevices can unlock the devices.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189 */
190static void lock_swapdevices(void)
191{
192 int i;
193
Hugh Dickinsdae06ac2005-09-03 15:54:42 -0700194 spin_lock(&swap_lock);
Pavel Machek2e4d5822005-06-25 14:55:12 -0700195 for (i = 0; i< MAX_SWAPFILES; i++)
196 if (swapfile_used[i] == SWAPFILE_IGNORED) {
Hugh Dickinsdae06ac2005-09-03 15:54:42 -0700197 swap_info[i].flags ^= SWP_WRITEOK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198 }
Hugh Dickinsdae06ac2005-09-03 15:54:42 -0700199 spin_unlock(&swap_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200}
201
202/**
Pavel Machek8686bcd2005-09-22 21:44:11 -0700203 * write_page - Write one page to a fresh swap location.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204 * @addr: Address we're writing.
205 * @loc: Place to store the entry we used.
206 *
207 * Allocate a new swap entry and 'sync' it. Note we discard -EIO
Pavel Machek2e4d5822005-06-25 14:55:12 -0700208 * errors. That is an artifact left over from swsusp. It did not
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209 * check the return of rw_swap_page_sync() at all, since most pages
210 * written back to swap would return -EIO.
211 * This is a partial improvement, since we will at least return other
212 * errors, though we need to eventually fix the damn code.
213 */
Pavel Machekdc19d502005-11-07 00:58:40 -0800214static int write_page(unsigned long addr, swp_entry_t *loc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215{
216 swp_entry_t entry;
217 int error = 0;
218
219 entry = get_swap_page();
Pavel Machek2e4d5822005-06-25 14:55:12 -0700220 if (swp_offset(entry) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221 swapfile_used[swp_type(entry)] == SWAPFILE_SUSPEND) {
222 error = rw_swap_page_sync(WRITE, entry,
223 virt_to_page(addr));
224 if (error == -EIO)
225 error = 0;
226 if (!error)
227 *loc = entry;
228 } else
229 error = -ENOSPC;
230 return error;
231}
232
233/**
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -0800234 * Swap map-handling functions
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235 *
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -0800236 * The swap map is a data structure used for keeping track of each page
237 * written to the swap. It consists of many swap_map_page structures
238 * that contain each an array of MAP_PAGE_SIZE swap entries.
239 * These structures are linked together with the help of either the
240 * .next (in memory) or the .next_swap (in swap) member.
241 *
242 * The swap map is created during suspend. At that time we need to keep
243 * it in memory, because we have to free all of the allocated swap
244 * entries if an error occurs. The memory needed is preallocated
245 * so that we know in advance if there's enough of it.
246 *
247 * The first swap_map_page structure is filled with the swap entries that
248 * correspond to the first MAP_PAGE_SIZE data pages written to swap and
249 * so on. After the all of the data pages have been written, the order
250 * of the swap_map_page structures in the map is reversed so that they
251 * can be read from swap in the original order. This causes the data
252 * pages to be loaded in exactly the same order in which they have been
253 * saved.
254 *
255 * During resume we only need to use one swap_map_page structure
256 * at a time, which means that we only need to use two memory pages for
257 * reading the image - one for reading the swap_map_page structures
258 * and the second for reading the data pages from swap.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -0800261#define MAP_PAGE_SIZE ((PAGE_SIZE - sizeof(swp_entry_t) - sizeof(void *)) \
262 / sizeof(swp_entry_t))
263
264struct swap_map_page {
265 swp_entry_t entries[MAP_PAGE_SIZE];
266 swp_entry_t next_swap;
267 struct swap_map_page *next;
268};
269
270static inline void free_swap_map(struct swap_map_page *swap_map)
271{
272 struct swap_map_page *swp;
273
274 while (swap_map) {
275 swp = swap_map->next;
276 free_page((unsigned long)swap_map);
277 swap_map = swp;
278 }
279}
280
281static struct swap_map_page *alloc_swap_map(unsigned int nr_pages)
282{
283 struct swap_map_page *swap_map, *swp;
284 unsigned n = 0;
285
286 if (!nr_pages)
287 return NULL;
288
289 pr_debug("alloc_swap_map(): nr_pages = %d\n", nr_pages);
290 swap_map = (struct swap_map_page *)get_zeroed_page(GFP_ATOMIC);
291 swp = swap_map;
292 for (n = MAP_PAGE_SIZE; n < nr_pages; n += MAP_PAGE_SIZE) {
293 swp->next = (struct swap_map_page *)get_zeroed_page(GFP_ATOMIC);
294 swp = swp->next;
295 if (!swp) {
296 free_swap_map(swap_map);
297 return NULL;
298 }
299 }
300 return swap_map;
301}
302
303/**
304 * reverse_swap_map - reverse the order of pages in the swap map
305 * @swap_map
306 */
307
308static inline struct swap_map_page *reverse_swap_map(struct swap_map_page *swap_map)
309{
310 struct swap_map_page *prev, *next;
311
312 prev = NULL;
313 while (swap_map) {
314 next = swap_map->next;
315 swap_map->next = prev;
316 prev = swap_map;
317 swap_map = next;
318 }
319 return prev;
320}
321
322/**
323 * free_swap_map_entries - free the swap entries allocated to store
324 * the swap map @swap_map (this is only called in case of an error)
325 */
326static inline void free_swap_map_entries(struct swap_map_page *swap_map)
327{
328 while (swap_map) {
329 if (swap_map->next_swap.val)
330 swap_free(swap_map->next_swap);
331 swap_map = swap_map->next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 }
333}
334
335/**
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -0800336 * save_swap_map - save the swap map used for tracing the data pages
337 * stored in the swap
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 */
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -0800339
340static int save_swap_map(struct swap_map_page *swap_map, swp_entry_t *start)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341{
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -0800342 swp_entry_t entry = (swp_entry_t){0};
343 int error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -0800345 while (swap_map) {
346 swap_map->next_swap = entry;
347 if ((error = write_page((unsigned long)swap_map, &entry)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348 return error;
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -0800349 swap_map = swap_map->next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350 }
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -0800351 *start = entry;
352 return 0;
353}
354
355/**
356 * free_image_entries - free the swap entries allocated to store
357 * the image data pages (this is only called in case of an error)
358 */
359
360static inline void free_image_entries(struct swap_map_page *swp)
361{
362 unsigned k;
363
364 while (swp) {
365 for (k = 0; k < MAP_PAGE_SIZE; k++)
366 if (swp->entries[k].val)
367 swap_free(swp->entries[k]);
368 swp = swp->next;
369 }
370}
371
372/**
373 * The swap_map_handle structure is used for handling the swap map in
374 * a file-alike way
375 */
376
377struct swap_map_handle {
378 struct swap_map_page *cur;
379 unsigned int k;
380};
381
382static inline void init_swap_map_handle(struct swap_map_handle *handle,
383 struct swap_map_page *map)
384{
385 handle->cur = map;
386 handle->k = 0;
387}
388
389static inline int swap_map_write_page(struct swap_map_handle *handle,
390 unsigned long addr)
391{
392 int error;
393
394 error = write_page(addr, handle->cur->entries + handle->k);
395 if (error)
396 return error;
397 if (++handle->k >= MAP_PAGE_SIZE) {
398 handle->cur = handle->cur->next;
399 handle->k = 0;
400 }
401 return 0;
402}
403
404/**
405 * save_image_data - save the data pages pointed to by the PBEs
406 * from the list @pblist using the swap map handle @handle
407 * (assume there are @nr_pages data pages to save)
408 */
409
410static int save_image_data(struct pbe *pblist,
411 struct swap_map_handle *handle,
412 unsigned int nr_pages)
413{
414 unsigned int m;
415 struct pbe *p;
416 int error = 0;
417
418 printk("Saving image data pages (%u pages) ... ", nr_pages);
419 m = nr_pages / 100;
420 if (!m)
421 m = 1;
422 nr_pages = 0;
423 for_each_pbe (p, pblist) {
424 error = swap_map_write_page(handle, p->address);
425 if (error)
426 break;
427 if (!(nr_pages % m))
428 printk("\b\b\b\b%3d%%", nr_pages / m);
429 nr_pages++;
430 }
431 if (!error)
432 printk("\b\b\b\bdone\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 return error;
434}
435
436static void dump_info(void)
437{
438 pr_debug(" swsusp: Version: %u\n",swsusp_info.version_code);
439 pr_debug(" swsusp: Num Pages: %ld\n",swsusp_info.num_physpages);
440 pr_debug(" swsusp: UTS Sys: %s\n",swsusp_info.uts.sysname);
441 pr_debug(" swsusp: UTS Node: %s\n",swsusp_info.uts.nodename);
442 pr_debug(" swsusp: UTS Release: %s\n",swsusp_info.uts.release);
443 pr_debug(" swsusp: UTS Version: %s\n",swsusp_info.uts.version);
444 pr_debug(" swsusp: UTS Machine: %s\n",swsusp_info.uts.machine);
445 pr_debug(" swsusp: UTS Domain: %s\n",swsusp_info.uts.domainname);
446 pr_debug(" swsusp: CPUs: %d\n",swsusp_info.cpus);
447 pr_debug(" swsusp: Image: %ld Pages\n",swsusp_info.image_pages);
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -0800448 pr_debug(" swsusp: Total: %ld Pages\n", swsusp_info.pages);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449}
450
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -0800451static void init_header(unsigned int nr_pages)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452{
453 memset(&swsusp_info, 0, sizeof(swsusp_info));
454 swsusp_info.version_code = LINUX_VERSION_CODE;
455 swsusp_info.num_physpages = num_physpages;
456 memcpy(&swsusp_info.uts, &system_utsname, sizeof(system_utsname));
457
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458 swsusp_info.cpus = num_online_cpus();
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -0800459 swsusp_info.image_pages = nr_pages;
460 swsusp_info.pages = nr_pages +
461 ((nr_pages * sizeof(long) + PAGE_SIZE - 1) >> PAGE_SHIFT);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462}
463
464static int close_swap(void)
465{
466 swp_entry_t entry;
467 int error;
468
469 dump_info();
470 error = write_page((unsigned long)&swsusp_info, &entry);
Pavel Machek2e4d5822005-06-25 14:55:12 -0700471 if (!error) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 printk( "S" );
473 error = mark_swapfiles(entry);
474 printk( "|\n" );
475 }
476 return error;
477}
478
479/**
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -0800480 * pack_orig_addresses - the .orig_address fields of the PBEs from the
481 * list starting at @pbe are stored in the array @buf[] (1 page)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 */
483
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -0800484static inline struct pbe *pack_orig_addresses(unsigned long *buf,
485 struct pbe *pbe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486{
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -0800487 int j;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -0800489 for (j = 0; j < PAGE_SIZE / sizeof(long) && pbe; j++) {
490 buf[j] = pbe->orig_address;
491 pbe = pbe->next;
492 }
493 if (!pbe)
494 for (; j < PAGE_SIZE / sizeof(long); j++)
495 buf[j] = 0;
496 return pbe;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497}
498
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499/**
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -0800500 * save_image_metadata - save the .orig_address fields of the PBEs
501 * from the list @pblist using the swap map handle @handle
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502 */
503
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -0800504static int save_image_metadata(struct pbe *pblist,
505 struct swap_map_handle *handle)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506{
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -0800507 unsigned long *buf;
Pavel Machekdc19d502005-11-07 00:58:40 -0800508 unsigned int n = 0;
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -0800509 struct pbe *p;
510 int error = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -0800512 printk("Saving image metadata ... ");
513 buf = (unsigned long *)get_zeroed_page(GFP_ATOMIC);
514 if (!buf)
515 return -ENOMEM;
516 p = pblist;
517 while (p) {
518 p = pack_orig_addresses(buf, p);
519 error = swap_map_write_page(handle, (unsigned long)buf);
520 if (error)
521 break;
522 n++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 }
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -0800524 free_page((unsigned long)buf);
525 if (!error)
526 printk("done (%u pages saved)\n", n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527 return error;
528}
529
530/**
Rafael J. Wysocki0fbeb5a2005-11-08 21:34:41 -0800531 * enough_swap - Make sure we have enough swap to save the image.
532 *
533 * Returns TRUE or FALSE after checking the total amount of swap
534 * space avaiable.
535 *
536 * FIXME: si_swapinfo(&i) returns all swap devices information.
537 * We should only consider resume_device.
538 */
539
540static int enough_swap(unsigned int nr_pages)
541{
542 struct sysinfo i;
543
544 si_swapinfo(&i);
545 pr_debug("swsusp: available swap: %lu pages\n", i.freeswap);
546 return i.freeswap > (nr_pages + PAGES_FOR_IO +
547 (nr_pages + PBES_PER_PAGE - 1) / PBES_PER_PAGE);
548}
549
550/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551 * write_suspend_image - Write entire image and metadata.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552 */
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -0800553static int write_suspend_image(struct pbe *pblist, unsigned int nr_pages)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554{
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -0800555 struct swap_map_page *swap_map;
556 struct swap_map_handle handle;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 int error;
558
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -0800559 if (!enough_swap(nr_pages)) {
Rafael J. Wysocki0fbeb5a2005-11-08 21:34:41 -0800560 printk(KERN_ERR "swsusp: Not enough free swap\n");
561 return -ENOSPC;
562 }
563
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -0800564 init_header(nr_pages);
565 swap_map = alloc_swap_map(swsusp_info.pages);
566 if (!swap_map)
567 return -ENOMEM;
568 init_swap_map_handle(&handle, swap_map);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -0800570 error = save_image_metadata(pblist, &handle);
571 if (!error)
572 error = save_image_data(pblist, &handle, nr_pages);
573 if (error)
574 goto Free_image_entries;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -0800576 swap_map = reverse_swap_map(swap_map);
577 error = save_swap_map(swap_map, &swsusp_info.start);
578 if (error)
579 goto Free_map_entries;
580
581 error = close_swap();
582 if (error)
583 goto Free_map_entries;
584
585Free_swap_map:
586 free_swap_map(swap_map);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587 return error;
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -0800588
589Free_map_entries:
590 free_swap_map_entries(swap_map);
591Free_image_entries:
592 free_image_entries(swap_map);
593 goto Free_swap_map;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594}
595
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596/* It is important _NOT_ to umount filesystems at this point. We want
597 * them synced (in case something goes wrong) but we DO not want to mark
598 * filesystem clean: it is not. (And it does not matter, if we resume
599 * correctly, we'll mark system clean, anyway.)
600 */
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -0800601int swsusp_write(struct pbe *pblist, unsigned int nr_pages)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602{
603 int error;
Rafael J. Wysocki0245b3e2005-10-30 15:00:01 -0800604
Rafael J. Wysocki0fbeb5a2005-11-08 21:34:41 -0800605 if ((error = swsusp_swap_check())) {
606 printk(KERN_ERR "swsusp: cannot find swap device, try swapon -a.\n");
607 return error;
608 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 lock_swapdevices();
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -0800610 error = write_suspend_image(pblist, nr_pages);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611 /* This will unlock ignored swap devices since writing is finished */
612 lock_swapdevices();
613 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614}
615
Rafael J. Wysocki72a97e02006-01-06 00:13:46 -0800616/**
617 * swsusp_shrink_memory - Try to free as much memory as needed
618 *
619 * ... but do not OOM-kill anyone
620 *
621 * Notice: all userland should be stopped before it is called, or
622 * livelock is possible.
623 */
624
625#define SHRINK_BITE 10000
626
627int swsusp_shrink_memory(void)
628{
629 long tmp;
630 struct zone *zone;
631 unsigned long pages = 0;
632 unsigned int i = 0;
633 char *p = "-\\|/";
634
635 printk("Shrinking memory... ");
636 do {
637#ifdef FAST_FREE
638 tmp = 2 * count_highmem_pages();
639 tmp += tmp / 50 + count_data_pages();
640 tmp += (tmp + PBES_PER_PAGE - 1) / PBES_PER_PAGE +
641 PAGES_FOR_IO;
642 for_each_zone (zone)
643 if (!is_highmem(zone))
644 tmp -= zone->free_pages;
645 if (tmp > 0) {
646 tmp = shrink_all_memory(SHRINK_BITE);
647 if (!tmp)
648 return -ENOMEM;
649 pages += tmp;
650 }
651#else
652 tmp = shrink_all_memory(SHRINK_BITE);
653 pages += tmp;
654#endif
655 printk("\b%c", p[i++%4]);
656 } while (tmp > 0);
657 printk("\bdone (%lu pages freed)\n", pages);
658
659 return 0;
660}
661
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662int swsusp_suspend(void)
663{
664 int error;
Rafael J. Wysocki0fbeb5a2005-11-08 21:34:41 -0800665
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 if ((error = arch_prepare_suspend()))
667 return error;
668 local_irq_disable();
669 /* At this point, device_suspend() has been called, but *not*
670 * device_power_down(). We *must* device_power_down() now.
671 * Otherwise, drivers for some devices (e.g. interrupt controllers)
672 * become desynchronized with the actual state of the hardware
673 * at resume time, and evil weirdness ensues.
674 */
675 if ((error = device_power_down(PMSG_FREEZE))) {
Pavel Machek99dc7d62005-09-03 15:57:05 -0700676 printk(KERN_ERR "Some devices failed to power down, aborting suspend\n");
Rafael J. Wysocki0fbeb5a2005-11-08 21:34:41 -0800677 goto Enable_irqs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678 }
Pavel Machek47b724f2005-07-07 17:56:44 -0700679
Rafael J. Wysocki0fbeb5a2005-11-08 21:34:41 -0800680 if ((error = save_highmem())) {
681 printk(KERN_ERR "swsusp: Not enough free pages for highmem\n");
682 goto Restore_highmem;
Pavel Machek47b724f2005-07-07 17:56:44 -0700683 }
684
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 save_processor_state();
686 if ((error = swsusp_arch_suspend()))
Pavel Machek99dc7d62005-09-03 15:57:05 -0700687 printk(KERN_ERR "Error %d suspending\n", error);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688 /* Restore control flow magically appears here */
689 restore_processor_state();
Rafael J. Wysocki0fbeb5a2005-11-08 21:34:41 -0800690Restore_highmem:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 restore_highmem();
692 device_power_up();
Rafael J. Wysocki0fbeb5a2005-11-08 21:34:41 -0800693Enable_irqs:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 local_irq_enable();
695 return error;
696}
697
698int swsusp_resume(void)
699{
700 int error;
701 local_irq_disable();
702 if (device_power_down(PMSG_FREEZE))
703 printk(KERN_ERR "Some devices failed to power down, very bad\n");
704 /* We'll ignore saved state, but this gets preempt count (etc) right */
705 save_processor_state();
706 error = swsusp_arch_resume();
707 /* Code below is only ever reached in case of failure. Otherwise
708 * execution continues at place where swsusp_arch_suspend was called
709 */
710 BUG_ON(!error);
Rafael J. Wysocki2c1b4a52005-10-30 14:59:58 -0800711 /* The only reason why swsusp_arch_resume() can fail is memory being
712 * very tight, so we have to free it as soon as we can to avoid
713 * subsequent failures
714 */
715 swsusp_free();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 restore_processor_state();
717 restore_highmem();
Ingo Molnar8446f1d2005-09-06 15:16:27 -0700718 touch_softlockup_watchdog();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719 device_power_up();
720 local_irq_enable();
721 return error;
722}
723
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724/**
Rafael J. Wysockied14b522005-11-08 21:34:40 -0800725 * mark_unsafe_pages - mark the pages that cannot be used for storing
726 * the image during resume, because they conflict with the pages that
727 * had been used before suspend
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 */
729
Rafael J. Wysockied14b522005-11-08 21:34:40 -0800730static void mark_unsafe_pages(struct pbe *pblist)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731{
732 struct zone *zone;
733 unsigned long zone_pfn;
Rafael J. Wysockied14b522005-11-08 21:34:40 -0800734 struct pbe *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735
736 if (!pblist) /* a sanity check */
Rafael J. Wysockied14b522005-11-08 21:34:40 -0800737 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738
Rafael J. Wysocki2c1b4a52005-10-30 14:59:58 -0800739 /* Clear page flags */
Pavel Machek2e4d5822005-06-25 14:55:12 -0700740 for_each_zone (zone) {
Rafael J. Wysockied14b522005-11-08 21:34:40 -0800741 for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn)
742 if (pfn_valid(zone_pfn + zone->zone_start_pfn))
743 ClearPageNosaveFree(pfn_to_page(zone_pfn +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 zone->zone_start_pfn));
745 }
746
Rafael J. Wysocki2c1b4a52005-10-30 14:59:58 -0800747 /* Mark orig addresses */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748 for_each_pbe (p, pblist)
Rafael J. Wysocki2c1b4a52005-10-30 14:59:58 -0800749 SetPageNosaveFree(virt_to_page(p->orig_address));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750
Rafael J. Wysockied14b522005-11-08 21:34:40 -0800751}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752
Rafael J. Wysockied14b522005-11-08 21:34:40 -0800753static void copy_page_backup_list(struct pbe *dst, struct pbe *src)
754{
755 /* We assume both lists contain the same number of elements */
756 while (src) {
757 dst->orig_address = src->orig_address;
Rafael J. Wysockied14b522005-11-08 21:34:40 -0800758 dst = dst->next;
759 src = src->next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761}
762
Pavel Pisa4dc3b162005-05-01 08:59:25 -0700763/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 * Using bio to read from swap.
765 * This code requires a bit more work than just using buffer heads
766 * but, it is the recommended way for 2.5/2.6.
767 * The following are to signal the beginning and end of I/O. Bios
768 * finish asynchronously, while we want them to happen synchronously.
769 * A simple atomic_t, and a wait loop take care of this problem.
770 */
771
772static atomic_t io_done = ATOMIC_INIT(0);
773
Pavel Machekdc19d502005-11-07 00:58:40 -0800774static int end_io(struct bio *bio, unsigned int num, int err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775{
776 if (!test_bit(BIO_UPTODATE, &bio->bi_flags))
777 panic("I/O error reading memory image");
778 atomic_set(&io_done, 0);
779 return 0;
780}
781
Pavel Machekdc19d502005-11-07 00:58:40 -0800782static struct block_device *resume_bdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783
784/**
785 * submit - submit BIO request.
786 * @rw: READ or WRITE.
787 * @off physical offset of page.
788 * @page: page we're reading or writing.
789 *
790 * Straight from the textbook - allocate and initialize the bio.
791 * If we're writing, make sure the page is marked as dirty.
792 * Then submit it and wait.
793 */
794
Pavel Machekdc19d502005-11-07 00:58:40 -0800795static int submit(int rw, pgoff_t page_off, void *page)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796{
797 int error = 0;
Pavel Machekdc19d502005-11-07 00:58:40 -0800798 struct bio *bio;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799
800 bio = bio_alloc(GFP_ATOMIC, 1);
801 if (!bio)
802 return -ENOMEM;
803 bio->bi_sector = page_off * (PAGE_SIZE >> 9);
804 bio_get(bio);
805 bio->bi_bdev = resume_bdev;
806 bio->bi_end_io = end_io;
807
808 if (bio_add_page(bio, virt_to_page(page), PAGE_SIZE, 0) < PAGE_SIZE) {
809 printk("swsusp: ERROR: adding page to bio at %ld\n",page_off);
810 error = -EFAULT;
811 goto Done;
812 }
813
814 if (rw == WRITE)
815 bio_set_pages_dirty(bio);
816
817 atomic_set(&io_done, 1);
818 submit_bio(rw | (1 << BIO_RW_SYNC), bio);
819 while (atomic_read(&io_done))
820 yield();
821
822 Done:
823 bio_put(bio);
824 return error;
825}
826
Pavel Machekdc19d502005-11-07 00:58:40 -0800827static int bio_read_page(pgoff_t page_off, void *page)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828{
829 return submit(READ, page_off, page);
830}
831
Pavel Machekdc19d502005-11-07 00:58:40 -0800832static int bio_write_page(pgoff_t page_off, void *page)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833{
834 return submit(WRITE, page_off, page);
835}
836
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -0800837/**
838 * The following functions allow us to read data using a swap map
839 * in a file-alike way
840 */
841
842static inline void release_swap_map_reader(struct swap_map_handle *handle)
843{
844 if (handle->cur)
845 free_page((unsigned long)handle->cur);
846 handle->cur = NULL;
847}
848
849static inline int get_swap_map_reader(struct swap_map_handle *handle,
850 swp_entry_t start)
851{
852 int error;
853
854 if (!swp_offset(start))
855 return -EINVAL;
856 handle->cur = (struct swap_map_page *)get_zeroed_page(GFP_ATOMIC);
857 if (!handle->cur)
858 return -ENOMEM;
859 error = bio_read_page(swp_offset(start), handle->cur);
860 if (error) {
861 release_swap_map_reader(handle);
862 return error;
863 }
864 handle->k = 0;
865 return 0;
866}
867
868static inline int swap_map_read_page(struct swap_map_handle *handle, void *buf)
869{
870 unsigned long offset;
871 int error;
872
873 if (!handle->cur)
874 return -EINVAL;
875 offset = swp_offset(handle->cur->entries[handle->k]);
876 if (!offset)
877 return -EINVAL;
878 error = bio_read_page(offset, buf);
879 if (error)
880 return error;
881 if (++handle->k >= MAP_PAGE_SIZE) {
882 handle->k = 0;
883 offset = swp_offset(handle->cur->next_swap);
884 if (!offset)
885 release_swap_map_reader(handle);
886 else
887 error = bio_read_page(offset, handle->cur);
888 }
889 return error;
890}
891
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892/*
893 * Sanity check if this image makes sense with this kernel/swap context
894 * I really don't think that it's foolproof but more than nothing..
895 */
896
Pavel Machekdc19d502005-11-07 00:58:40 -0800897static const char *sanity_check(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898{
899 dump_info();
Pavel Machek47b724f2005-07-07 17:56:44 -0700900 if (swsusp_info.version_code != LINUX_VERSION_CODE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901 return "kernel version";
Pavel Machek47b724f2005-07-07 17:56:44 -0700902 if (swsusp_info.num_physpages != num_physpages)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 return "memory size";
904 if (strcmp(swsusp_info.uts.sysname,system_utsname.sysname))
905 return "system type";
906 if (strcmp(swsusp_info.uts.release,system_utsname.release))
907 return "kernel release";
908 if (strcmp(swsusp_info.uts.version,system_utsname.version))
909 return "version";
910 if (strcmp(swsusp_info.uts.machine,system_utsname.machine))
911 return "machine";
Li Shaohua5a72e042005-06-25 14:55:06 -0700912#if 0
Pavel Machek99dc7d62005-09-03 15:57:05 -0700913 /* We can't use number of online CPUs when we use hotplug to remove them ;-))) */
914 if (swsusp_info.cpus != num_possible_cpus())
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915 return "number of cpus";
Li Shaohua5a72e042005-06-25 14:55:06 -0700916#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917 return NULL;
918}
919
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920static int check_header(void)
921{
Pavel Machekdc19d502005-11-07 00:58:40 -0800922 const char *reason = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923 int error;
924
925 if ((error = bio_read_page(swp_offset(swsusp_header.swsusp_info), &swsusp_info)))
926 return error;
927
928 /* Is this same machine? */
929 if ((reason = sanity_check())) {
930 printk(KERN_ERR "swsusp: Resume mismatch: %s\n",reason);
931 return -EPERM;
932 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933 return error;
934}
935
936static int check_sig(void)
937{
938 int error;
939
940 memset(&swsusp_header, 0, sizeof(swsusp_header));
941 if ((error = bio_read_page(0, &swsusp_header)))
942 return error;
943 if (!memcmp(SWSUSP_SIG, swsusp_header.sig, 10)) {
944 memcpy(swsusp_header.sig, swsusp_header.orig_sig, 10);
945
946 /*
947 * Reset swap signature now.
948 */
949 error = bio_write_page(0, &swsusp_header);
Rafael J. Wysocki0fbeb5a2005-11-08 21:34:41 -0800950 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951 return -EINVAL;
952 }
953 if (!error)
954 pr_debug("swsusp: Signature found, resuming\n");
955 return error;
956}
957
958/**
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -0800959 * load_image_data - load the image data using the swap map handle
960 * @handle and store them using the page backup list @pblist
961 * (assume there are @nr_pages pages to load)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962 */
963
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -0800964static int load_image_data(struct pbe *pblist,
965 struct swap_map_handle *handle,
966 unsigned int nr_pages)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967{
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -0800968 int error;
969 unsigned int m;
Pavel Machekdc19d502005-11-07 00:58:40 -0800970 struct pbe *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -0800972 if (!pblist)
973 return -EINVAL;
974 printk("Loading image data pages (%u pages) ... ", nr_pages);
975 m = nr_pages / 100;
976 if (!m)
977 m = 1;
978 nr_pages = 0;
979 p = pblist;
980 while (p) {
981 error = swap_map_read_page(handle, (void *)p->address);
982 if (error)
983 break;
984 p = p->next;
985 if (!(nr_pages % m))
986 printk("\b\b\b\b%3d%%", nr_pages / m);
987 nr_pages++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988 }
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -0800989 if (!error)
990 printk("\b\b\b\bdone\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991 return error;
992}
993
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994/**
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -0800995 * unpack_orig_addresses - copy the elements of @buf[] (1 page) to
996 * the PBEs in the list starting at @pbe
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997 */
998
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -0800999static inline struct pbe *unpack_orig_addresses(unsigned long *buf,
1000 struct pbe *pbe)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001{
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -08001002 int j;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -08001004 for (j = 0; j < PAGE_SIZE / sizeof(long) && pbe; j++) {
1005 pbe->orig_address = buf[j];
1006 pbe = pbe->next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 }
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -08001008 return pbe;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009}
1010
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -08001011/**
1012 * load_image_metadata - load the image metadata using the swap map
1013 * handle @handle and put them into the PBEs in the list @pblist
1014 */
1015
1016static int load_image_metadata(struct pbe *pblist, struct swap_map_handle *handle)
1017{
1018 struct pbe *p;
1019 unsigned long *buf;
1020 unsigned int n = 0;
1021 int error = 0;
1022
1023 printk("Loading image metadata ... ");
1024 buf = (unsigned long *)get_zeroed_page(GFP_ATOMIC);
1025 if (!buf)
1026 return -ENOMEM;
1027 p = pblist;
1028 while (p) {
1029 error = swap_map_read_page(handle, buf);
1030 if (error)
1031 break;
1032 p = unpack_orig_addresses(buf, p);
1033 n++;
1034 }
1035 free_page((unsigned long)buf);
1036 if (!error)
1037 printk("done (%u pages loaded)\n", n);
1038 return error;
1039}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040
1041static int check_suspend_image(void)
1042{
1043 int error = 0;
1044
1045 if ((error = check_sig()))
1046 return error;
1047
1048 if ((error = check_header()))
1049 return error;
1050
1051 return 0;
1052}
1053
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -08001054static int read_suspend_image(struct pbe **pblist_ptr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055{
1056 int error = 0;
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -08001057 struct pbe *p, *pblist;
1058 struct swap_map_handle handle;
1059 unsigned int nr_pages = swsusp_info.image_pages;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -08001061 p = alloc_pagedir(nr_pages, GFP_ATOMIC, 0);
1062 if (!p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063 return -ENOMEM;
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -08001064 error = get_swap_map_reader(&handle, swsusp_info.start);
1065 if (error)
1066 /* The PBE list at p will be released by swsusp_free() */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067 return error;
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -08001068 error = load_image_metadata(p, &handle);
1069 if (!error) {
1070 mark_unsafe_pages(p);
1071 pblist = alloc_pagedir(nr_pages, GFP_ATOMIC, 1);
1072 if (pblist)
1073 copy_page_backup_list(pblist, p);
1074 free_pagedir(p);
1075 if (!pblist)
1076 error = -ENOMEM;
1077
1078 /* Allocate memory for the image and read the data from swap */
1079 if (!error)
1080 error = alloc_data_pages(pblist, GFP_ATOMIC, 1);
Rafael J. Wysocki72a97e02006-01-06 00:13:46 -08001081 if (!error) {
1082 release_eaten_pages();
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -08001083 error = load_image_data(pblist, &handle, nr_pages);
Rafael J. Wysocki72a97e02006-01-06 00:13:46 -08001084 }
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -08001085 if (!error)
1086 *pblist_ptr = pblist;
Rafael J. Wysockied14b522005-11-08 21:34:40 -08001087 }
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -08001088 release_swap_map_reader(&handle);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089 return error;
1090}
1091
1092/**
1093 * swsusp_check - Check for saved image in swap
1094 */
1095
1096int swsusp_check(void)
1097{
1098 int error;
1099
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100 resume_bdev = open_by_devnum(swsusp_resume_device, FMODE_READ);
1101 if (!IS_ERR(resume_bdev)) {
1102 set_blocksize(resume_bdev, PAGE_SIZE);
1103 error = check_suspend_image();
1104 if (error)
1105 blkdev_put(resume_bdev);
1106 } else
1107 error = PTR_ERR(resume_bdev);
1108
1109 if (!error)
1110 pr_debug("swsusp: resume file found\n");
1111 else
1112 pr_debug("swsusp: Error %d check for resume file\n", error);
1113 return error;
1114}
1115
1116/**
1117 * swsusp_read - Read saved image from swap.
1118 */
1119
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -08001120int swsusp_read(struct pbe **pblist_ptr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121{
1122 int error;
1123
1124 if (IS_ERR(resume_bdev)) {
1125 pr_debug("swsusp: block device not initialised\n");
1126 return PTR_ERR(resume_bdev);
1127 }
1128
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -08001129 error = read_suspend_image(pblist_ptr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130 blkdev_put(resume_bdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131
1132 if (!error)
1133 pr_debug("swsusp: Reading resume file was successful\n");
1134 else
1135 pr_debug("swsusp: Error %d resuming\n", error);
1136 return error;
1137}
1138
1139/**
1140 * swsusp_close - close swap device.
1141 */
1142
1143void swsusp_close(void)
1144{
1145 if (IS_ERR(resume_bdev)) {
1146 pr_debug("swsusp: block device not initialised\n");
1147 return;
1148 }
1149
1150 blkdev_put(resume_bdev);
1151}