blob: 6d5ceaf4c36478edee65dffc4562a2e4b00d9687 [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{
Rafael J. Wysockib3a93a22006-01-06 00:15:22 -0800629 long size, tmp;
Rafael J. Wysocki72a97e02006-01-06 00:13:46 -0800630 struct zone *zone;
631 unsigned long pages = 0;
632 unsigned int i = 0;
633 char *p = "-\\|/";
634
635 printk("Shrinking memory... ");
636 do {
Rafael J. Wysockib3a93a22006-01-06 00:15:22 -0800637 size = 2 * count_highmem_pages();
638 size += size / 50 + count_data_pages();
639 size += (size + PBES_PER_PAGE - 1) / PBES_PER_PAGE +
Rafael J. Wysocki72a97e02006-01-06 00:13:46 -0800640 PAGES_FOR_IO;
Rafael J. Wysockib3a93a22006-01-06 00:15:22 -0800641 tmp = size;
Rafael J. Wysocki72a97e02006-01-06 00:13:46 -0800642 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;
Rafael J. Wysockib3a93a22006-01-06 00:15:22 -0800650 } else if (size > (IMAGE_SIZE * 1024 * 1024) / PAGE_SIZE) {
651 tmp = shrink_all_memory(SHRINK_BITE);
652 pages += tmp;
Rafael J. Wysocki72a97e02006-01-06 00:13:46 -0800653 }
Rafael J. Wysocki72a97e02006-01-06 00:13:46 -0800654 printk("\b%c", p[i++%4]);
655 } while (tmp > 0);
656 printk("\bdone (%lu pages freed)\n", pages);
657
658 return 0;
659}
660
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661int swsusp_suspend(void)
662{
663 int error;
Rafael J. Wysocki0fbeb5a2005-11-08 21:34:41 -0800664
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 if ((error = arch_prepare_suspend()))
666 return error;
667 local_irq_disable();
668 /* At this point, device_suspend() has been called, but *not*
669 * device_power_down(). We *must* device_power_down() now.
670 * Otherwise, drivers for some devices (e.g. interrupt controllers)
671 * become desynchronized with the actual state of the hardware
672 * at resume time, and evil weirdness ensues.
673 */
674 if ((error = device_power_down(PMSG_FREEZE))) {
Pavel Machek99dc7d62005-09-03 15:57:05 -0700675 printk(KERN_ERR "Some devices failed to power down, aborting suspend\n");
Rafael J. Wysocki0fbeb5a2005-11-08 21:34:41 -0800676 goto Enable_irqs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 }
Pavel Machek47b724f2005-07-07 17:56:44 -0700678
Rafael J. Wysocki0fbeb5a2005-11-08 21:34:41 -0800679 if ((error = save_highmem())) {
680 printk(KERN_ERR "swsusp: Not enough free pages for highmem\n");
681 goto Restore_highmem;
Pavel Machek47b724f2005-07-07 17:56:44 -0700682 }
683
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 save_processor_state();
685 if ((error = swsusp_arch_suspend()))
Pavel Machek99dc7d62005-09-03 15:57:05 -0700686 printk(KERN_ERR "Error %d suspending\n", error);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 /* Restore control flow magically appears here */
688 restore_processor_state();
Rafael J. Wysocki0fbeb5a2005-11-08 21:34:41 -0800689Restore_highmem:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 restore_highmem();
691 device_power_up();
Rafael J. Wysocki0fbeb5a2005-11-08 21:34:41 -0800692Enable_irqs:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 local_irq_enable();
694 return error;
695}
696
697int swsusp_resume(void)
698{
699 int error;
700 local_irq_disable();
701 if (device_power_down(PMSG_FREEZE))
702 printk(KERN_ERR "Some devices failed to power down, very bad\n");
703 /* We'll ignore saved state, but this gets preempt count (etc) right */
704 save_processor_state();
705 error = swsusp_arch_resume();
706 /* Code below is only ever reached in case of failure. Otherwise
707 * execution continues at place where swsusp_arch_suspend was called
708 */
709 BUG_ON(!error);
Rafael J. Wysocki2c1b4a52005-10-30 14:59:58 -0800710 /* The only reason why swsusp_arch_resume() can fail is memory being
711 * very tight, so we have to free it as soon as we can to avoid
712 * subsequent failures
713 */
714 swsusp_free();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 restore_processor_state();
716 restore_highmem();
Ingo Molnar8446f1d2005-09-06 15:16:27 -0700717 touch_softlockup_watchdog();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 device_power_up();
719 local_irq_enable();
720 return error;
721}
722
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723/**
Rafael J. Wysockied14b522005-11-08 21:34:40 -0800724 * mark_unsafe_pages - mark the pages that cannot be used for storing
725 * the image during resume, because they conflict with the pages that
726 * had been used before suspend
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 */
728
Rafael J. Wysockied14b522005-11-08 21:34:40 -0800729static void mark_unsafe_pages(struct pbe *pblist)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730{
731 struct zone *zone;
732 unsigned long zone_pfn;
Rafael J. Wysockied14b522005-11-08 21:34:40 -0800733 struct pbe *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734
735 if (!pblist) /* a sanity check */
Rafael J. Wysockied14b522005-11-08 21:34:40 -0800736 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737
Rafael J. Wysocki2c1b4a52005-10-30 14:59:58 -0800738 /* Clear page flags */
Pavel Machek2e4d5822005-06-25 14:55:12 -0700739 for_each_zone (zone) {
Rafael J. Wysockied14b522005-11-08 21:34:40 -0800740 for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn)
741 if (pfn_valid(zone_pfn + zone->zone_start_pfn))
742 ClearPageNosaveFree(pfn_to_page(zone_pfn +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 zone->zone_start_pfn));
744 }
745
Rafael J. Wysocki2c1b4a52005-10-30 14:59:58 -0800746 /* Mark orig addresses */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747 for_each_pbe (p, pblist)
Rafael J. Wysocki2c1b4a52005-10-30 14:59:58 -0800748 SetPageNosaveFree(virt_to_page(p->orig_address));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749
Rafael J. Wysockied14b522005-11-08 21:34:40 -0800750}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751
Rafael J. Wysockied14b522005-11-08 21:34:40 -0800752static void copy_page_backup_list(struct pbe *dst, struct pbe *src)
753{
754 /* We assume both lists contain the same number of elements */
755 while (src) {
756 dst->orig_address = src->orig_address;
Rafael J. Wysockied14b522005-11-08 21:34:40 -0800757 dst = dst->next;
758 src = src->next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760}
761
Pavel Pisa4dc3b162005-05-01 08:59:25 -0700762/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 * Using bio to read from swap.
764 * This code requires a bit more work than just using buffer heads
765 * but, it is the recommended way for 2.5/2.6.
766 * The following are to signal the beginning and end of I/O. Bios
767 * finish asynchronously, while we want them to happen synchronously.
768 * A simple atomic_t, and a wait loop take care of this problem.
769 */
770
771static atomic_t io_done = ATOMIC_INIT(0);
772
Pavel Machekdc19d502005-11-07 00:58:40 -0800773static int end_io(struct bio *bio, unsigned int num, int err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774{
775 if (!test_bit(BIO_UPTODATE, &bio->bi_flags))
776 panic("I/O error reading memory image");
777 atomic_set(&io_done, 0);
778 return 0;
779}
780
Pavel Machekdc19d502005-11-07 00:58:40 -0800781static struct block_device *resume_bdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782
783/**
784 * submit - submit BIO request.
785 * @rw: READ or WRITE.
786 * @off physical offset of page.
787 * @page: page we're reading or writing.
788 *
789 * Straight from the textbook - allocate and initialize the bio.
790 * If we're writing, make sure the page is marked as dirty.
791 * Then submit it and wait.
792 */
793
Pavel Machekdc19d502005-11-07 00:58:40 -0800794static int submit(int rw, pgoff_t page_off, void *page)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795{
796 int error = 0;
Pavel Machekdc19d502005-11-07 00:58:40 -0800797 struct bio *bio;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798
799 bio = bio_alloc(GFP_ATOMIC, 1);
800 if (!bio)
801 return -ENOMEM;
802 bio->bi_sector = page_off * (PAGE_SIZE >> 9);
803 bio_get(bio);
804 bio->bi_bdev = resume_bdev;
805 bio->bi_end_io = end_io;
806
807 if (bio_add_page(bio, virt_to_page(page), PAGE_SIZE, 0) < PAGE_SIZE) {
808 printk("swsusp: ERROR: adding page to bio at %ld\n",page_off);
809 error = -EFAULT;
810 goto Done;
811 }
812
813 if (rw == WRITE)
814 bio_set_pages_dirty(bio);
815
816 atomic_set(&io_done, 1);
817 submit_bio(rw | (1 << BIO_RW_SYNC), bio);
818 while (atomic_read(&io_done))
819 yield();
820
821 Done:
822 bio_put(bio);
823 return error;
824}
825
Pavel Machekdc19d502005-11-07 00:58:40 -0800826static int bio_read_page(pgoff_t page_off, void *page)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827{
828 return submit(READ, page_off, page);
829}
830
Pavel Machekdc19d502005-11-07 00:58:40 -0800831static int bio_write_page(pgoff_t page_off, void *page)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832{
833 return submit(WRITE, page_off, page);
834}
835
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -0800836/**
837 * The following functions allow us to read data using a swap map
838 * in a file-alike way
839 */
840
841static inline void release_swap_map_reader(struct swap_map_handle *handle)
842{
843 if (handle->cur)
844 free_page((unsigned long)handle->cur);
845 handle->cur = NULL;
846}
847
848static inline int get_swap_map_reader(struct swap_map_handle *handle,
849 swp_entry_t start)
850{
851 int error;
852
853 if (!swp_offset(start))
854 return -EINVAL;
855 handle->cur = (struct swap_map_page *)get_zeroed_page(GFP_ATOMIC);
856 if (!handle->cur)
857 return -ENOMEM;
858 error = bio_read_page(swp_offset(start), handle->cur);
859 if (error) {
860 release_swap_map_reader(handle);
861 return error;
862 }
863 handle->k = 0;
864 return 0;
865}
866
867static inline int swap_map_read_page(struct swap_map_handle *handle, void *buf)
868{
869 unsigned long offset;
870 int error;
871
872 if (!handle->cur)
873 return -EINVAL;
874 offset = swp_offset(handle->cur->entries[handle->k]);
875 if (!offset)
876 return -EINVAL;
877 error = bio_read_page(offset, buf);
878 if (error)
879 return error;
880 if (++handle->k >= MAP_PAGE_SIZE) {
881 handle->k = 0;
882 offset = swp_offset(handle->cur->next_swap);
883 if (!offset)
884 release_swap_map_reader(handle);
885 else
886 error = bio_read_page(offset, handle->cur);
887 }
888 return error;
889}
890
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891/*
892 * Sanity check if this image makes sense with this kernel/swap context
893 * I really don't think that it's foolproof but more than nothing..
894 */
895
Pavel Machekdc19d502005-11-07 00:58:40 -0800896static const char *sanity_check(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897{
898 dump_info();
Pavel Machek47b724f2005-07-07 17:56:44 -0700899 if (swsusp_info.version_code != LINUX_VERSION_CODE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900 return "kernel version";
Pavel Machek47b724f2005-07-07 17:56:44 -0700901 if (swsusp_info.num_physpages != num_physpages)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 return "memory size";
903 if (strcmp(swsusp_info.uts.sysname,system_utsname.sysname))
904 return "system type";
905 if (strcmp(swsusp_info.uts.release,system_utsname.release))
906 return "kernel release";
907 if (strcmp(swsusp_info.uts.version,system_utsname.version))
908 return "version";
909 if (strcmp(swsusp_info.uts.machine,system_utsname.machine))
910 return "machine";
Li Shaohua5a72e042005-06-25 14:55:06 -0700911#if 0
Pavel Machek99dc7d62005-09-03 15:57:05 -0700912 /* We can't use number of online CPUs when we use hotplug to remove them ;-))) */
913 if (swsusp_info.cpus != num_possible_cpus())
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 return "number of cpus";
Li Shaohua5a72e042005-06-25 14:55:06 -0700915#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916 return NULL;
917}
918
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919static int check_header(void)
920{
Pavel Machekdc19d502005-11-07 00:58:40 -0800921 const char *reason = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922 int error;
923
924 if ((error = bio_read_page(swp_offset(swsusp_header.swsusp_info), &swsusp_info)))
925 return error;
926
927 /* Is this same machine? */
928 if ((reason = sanity_check())) {
929 printk(KERN_ERR "swsusp: Resume mismatch: %s\n",reason);
930 return -EPERM;
931 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932 return error;
933}
934
935static int check_sig(void)
936{
937 int error;
938
939 memset(&swsusp_header, 0, sizeof(swsusp_header));
940 if ((error = bio_read_page(0, &swsusp_header)))
941 return error;
942 if (!memcmp(SWSUSP_SIG, swsusp_header.sig, 10)) {
943 memcpy(swsusp_header.sig, swsusp_header.orig_sig, 10);
944
945 /*
946 * Reset swap signature now.
947 */
948 error = bio_write_page(0, &swsusp_header);
Rafael J. Wysocki0fbeb5a2005-11-08 21:34:41 -0800949 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950 return -EINVAL;
951 }
952 if (!error)
953 pr_debug("swsusp: Signature found, resuming\n");
954 return error;
955}
956
957/**
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -0800958 * load_image_data - load the image data using the swap map handle
959 * @handle and store them using the page backup list @pblist
960 * (assume there are @nr_pages pages to load)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961 */
962
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -0800963static int load_image_data(struct pbe *pblist,
964 struct swap_map_handle *handle,
965 unsigned int nr_pages)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966{
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -0800967 int error;
968 unsigned int m;
Pavel Machekdc19d502005-11-07 00:58:40 -0800969 struct pbe *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -0800971 if (!pblist)
972 return -EINVAL;
973 printk("Loading image data pages (%u pages) ... ", nr_pages);
974 m = nr_pages / 100;
975 if (!m)
976 m = 1;
977 nr_pages = 0;
978 p = pblist;
979 while (p) {
980 error = swap_map_read_page(handle, (void *)p->address);
981 if (error)
982 break;
983 p = p->next;
984 if (!(nr_pages % m))
985 printk("\b\b\b\b%3d%%", nr_pages / m);
986 nr_pages++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987 }
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -0800988 if (!error)
989 printk("\b\b\b\bdone\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990 return error;
991}
992
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993/**
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -0800994 * unpack_orig_addresses - copy the elements of @buf[] (1 page) to
995 * the PBEs in the list starting at @pbe
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 */
997
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -0800998static inline struct pbe *unpack_orig_addresses(unsigned long *buf,
999 struct pbe *pbe)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000{
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -08001001 int j;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -08001003 for (j = 0; j < PAGE_SIZE / sizeof(long) && pbe; j++) {
1004 pbe->orig_address = buf[j];
1005 pbe = pbe->next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006 }
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -08001007 return pbe;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008}
1009
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -08001010/**
1011 * load_image_metadata - load the image metadata using the swap map
1012 * handle @handle and put them into the PBEs in the list @pblist
1013 */
1014
1015static int load_image_metadata(struct pbe *pblist, struct swap_map_handle *handle)
1016{
1017 struct pbe *p;
1018 unsigned long *buf;
1019 unsigned int n = 0;
1020 int error = 0;
1021
1022 printk("Loading image metadata ... ");
1023 buf = (unsigned long *)get_zeroed_page(GFP_ATOMIC);
1024 if (!buf)
1025 return -ENOMEM;
1026 p = pblist;
1027 while (p) {
1028 error = swap_map_read_page(handle, buf);
1029 if (error)
1030 break;
1031 p = unpack_orig_addresses(buf, p);
1032 n++;
1033 }
1034 free_page((unsigned long)buf);
1035 if (!error)
1036 printk("done (%u pages loaded)\n", n);
1037 return error;
1038}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039
1040static int check_suspend_image(void)
1041{
1042 int error = 0;
1043
1044 if ((error = check_sig()))
1045 return error;
1046
1047 if ((error = check_header()))
1048 return error;
1049
1050 return 0;
1051}
1052
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -08001053static int read_suspend_image(struct pbe **pblist_ptr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054{
1055 int error = 0;
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -08001056 struct pbe *p, *pblist;
1057 struct swap_map_handle handle;
1058 unsigned int nr_pages = swsusp_info.image_pages;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -08001060 p = alloc_pagedir(nr_pages, GFP_ATOMIC, 0);
1061 if (!p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 return -ENOMEM;
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -08001063 error = get_swap_map_reader(&handle, swsusp_info.start);
1064 if (error)
1065 /* The PBE list at p will be released by swsusp_free() */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066 return error;
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -08001067 error = load_image_metadata(p, &handle);
1068 if (!error) {
1069 mark_unsafe_pages(p);
1070 pblist = alloc_pagedir(nr_pages, GFP_ATOMIC, 1);
1071 if (pblist)
1072 copy_page_backup_list(pblist, p);
1073 free_pagedir(p);
1074 if (!pblist)
1075 error = -ENOMEM;
1076
1077 /* Allocate memory for the image and read the data from swap */
1078 if (!error)
1079 error = alloc_data_pages(pblist, GFP_ATOMIC, 1);
Rafael J. Wysocki72a97e02006-01-06 00:13:46 -08001080 if (!error) {
1081 release_eaten_pages();
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -08001082 error = load_image_data(pblist, &handle, nr_pages);
Rafael J. Wysocki72a97e02006-01-06 00:13:46 -08001083 }
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -08001084 if (!error)
1085 *pblist_ptr = pblist;
Rafael J. Wysockied14b522005-11-08 21:34:40 -08001086 }
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -08001087 release_swap_map_reader(&handle);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088 return error;
1089}
1090
1091/**
1092 * swsusp_check - Check for saved image in swap
1093 */
1094
1095int swsusp_check(void)
1096{
1097 int error;
1098
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099 resume_bdev = open_by_devnum(swsusp_resume_device, FMODE_READ);
1100 if (!IS_ERR(resume_bdev)) {
1101 set_blocksize(resume_bdev, PAGE_SIZE);
1102 error = check_suspend_image();
1103 if (error)
1104 blkdev_put(resume_bdev);
1105 } else
1106 error = PTR_ERR(resume_bdev);
1107
1108 if (!error)
1109 pr_debug("swsusp: resume file found\n");
1110 else
1111 pr_debug("swsusp: Error %d check for resume file\n", error);
1112 return error;
1113}
1114
1115/**
1116 * swsusp_read - Read saved image from swap.
1117 */
1118
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -08001119int swsusp_read(struct pbe **pblist_ptr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120{
1121 int error;
1122
1123 if (IS_ERR(resume_bdev)) {
1124 pr_debug("swsusp: block device not initialised\n");
1125 return PTR_ERR(resume_bdev);
1126 }
1127
Rafael J. Wysocki7088a5c2006-01-06 00:13:05 -08001128 error = read_suspend_image(pblist_ptr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129 blkdev_put(resume_bdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130
1131 if (!error)
1132 pr_debug("swsusp: Reading resume file was successful\n");
1133 else
1134 pr_debug("swsusp: Error %d resuming\n", error);
1135 return error;
1136}
1137
1138/**
1139 * swsusp_close - close swap device.
1140 */
1141
1142void swsusp_close(void)
1143{
1144 if (IS_ERR(resume_bdev)) {
1145 pr_debug("swsusp: block device not initialised\n");
1146 return;
1147 }
1148
1149 blkdev_put(resume_bdev);
1150}