aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/power/snapshot.c
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2005-10-30 17:59:56 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2005-10-30 20:37:14 -0500
commit25761b6eb7b33823bcfff6bfe2a015badcd76fb8 (patch)
treea25841a3f4c4cf087ce75c0907c00966f19d339a /kernel/power/snapshot.c
parent351619baf9878731b4272fa10dda0f84f5582241 (diff)
[PATCH] swsusp: move snapshot functionality to separate file
The following patch moves the functionality of swsusp related to creating and handling the snapshot of memory to a separate file, snapshot.c This should enable us to untangle the code in the future and eventually to implement some parts of swsusp.c in the user space. The patch does not change the code. Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Signed-off-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/power/snapshot.c')
-rw-r--r--kernel/power/snapshot.c464
1 files changed, 464 insertions, 0 deletions
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c
new file mode 100644
index 000000000000..0f0a7f306b0d
--- /dev/null
+++ b/kernel/power/snapshot.c
@@ -0,0 +1,464 @@
1/*
2 * linux/kernel/power/swsusp.c
3 *
4 * This file is to realize architecture-independent
5 * machine suspend feature using pretty near only high-level routines
6 *
7 * Copyright (C) 1998-2005 Pavel Machek <pavel@suse.cz>
8 *
9 * This file is released under the GPLv2, and is based on swsusp.c.
10 *
11 */
12
13
14#include <linux/module.h>
15#include <linux/mm.h>
16#include <linux/suspend.h>
17#include <linux/smp_lock.h>
18#include <linux/file.h>
19#include <linux/utsname.h>
20#include <linux/version.h>
21#include <linux/delay.h>
22#include <linux/reboot.h>
23#include <linux/bitops.h>
24#include <linux/vt_kern.h>
25#include <linux/kbd_kern.h>
26#include <linux/keyboard.h>
27#include <linux/spinlock.h>
28#include <linux/genhd.h>
29#include <linux/kernel.h>
30#include <linux/major.h>
31#include <linux/swap.h>
32#include <linux/pm.h>
33#include <linux/device.h>
34#include <linux/buffer_head.h>
35#include <linux/swapops.h>
36#include <linux/bootmem.h>
37#include <linux/syscalls.h>
38#include <linux/console.h>
39#include <linux/highmem.h>
40#include <linux/bio.h>
41#include <linux/mount.h>
42
43#include <asm/uaccess.h>
44#include <asm/mmu_context.h>
45#include <asm/pgtable.h>
46#include <asm/tlbflush.h>
47#include <asm/io.h>
48
49#include <linux/random.h>
50#include <linux/crypto.h>
51#include <asm/scatterlist.h>
52
53#include "power.h"
54
55
56
57
58#ifdef CONFIG_HIGHMEM
59struct highmem_page {
60 char *data;
61 struct page *page;
62 struct highmem_page *next;
63};
64
65static struct highmem_page *highmem_copy;
66
67static int save_highmem_zone(struct zone *zone)
68{
69 unsigned long zone_pfn;
70 mark_free_pages(zone);
71 for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn) {
72 struct page *page;
73 struct highmem_page *save;
74 void *kaddr;
75 unsigned long pfn = zone_pfn + zone->zone_start_pfn;
76
77 if (!(pfn%1000))
78 printk(".");
79 if (!pfn_valid(pfn))
80 continue;
81 page = pfn_to_page(pfn);
82 /*
83 * This condition results from rvmalloc() sans vmalloc_32()
84 * and architectural memory reservations. This should be
85 * corrected eventually when the cases giving rise to this
86 * are better understood.
87 */
88 if (PageReserved(page)) {
89 printk("highmem reserved page?!\n");
90 continue;
91 }
92 BUG_ON(PageNosave(page));
93 if (PageNosaveFree(page))
94 continue;
95 save = kmalloc(sizeof(struct highmem_page), GFP_ATOMIC);
96 if (!save)
97 return -ENOMEM;
98 save->next = highmem_copy;
99 save->page = page;
100 save->data = (void *) get_zeroed_page(GFP_ATOMIC);
101 if (!save->data) {
102 kfree(save);
103 return -ENOMEM;
104 }
105 kaddr = kmap_atomic(page, KM_USER0);
106 memcpy(save->data, kaddr, PAGE_SIZE);
107 kunmap_atomic(kaddr, KM_USER0);
108 highmem_copy = save;
109 }
110 return 0;
111}
112#endif /* CONFIG_HIGHMEM */
113
114
115static int save_highmem(void)
116{
117#ifdef CONFIG_HIGHMEM
118 struct zone *zone;
119 int res = 0;
120
121 pr_debug("swsusp: Saving Highmem\n");
122 for_each_zone (zone) {
123 if (is_highmem(zone))
124 res = save_highmem_zone(zone);
125 if (res)
126 return res;
127 }
128#endif
129 return 0;
130}
131
132int restore_highmem(void)
133{
134#ifdef CONFIG_HIGHMEM
135 printk("swsusp: Restoring Highmem\n");
136 while (highmem_copy) {
137 struct highmem_page *save = highmem_copy;
138 void *kaddr;
139 highmem_copy = save->next;
140
141 kaddr = kmap_atomic(save->page, KM_USER0);
142 memcpy(kaddr, save->data, PAGE_SIZE);
143 kunmap_atomic(kaddr, KM_USER0);
144 free_page((long) save->data);
145 kfree(save);
146 }
147#endif
148 return 0;
149}
150
151
152static int pfn_is_nosave(unsigned long pfn)
153{
154 unsigned long nosave_begin_pfn = __pa(&__nosave_begin) >> PAGE_SHIFT;
155 unsigned long nosave_end_pfn = PAGE_ALIGN(__pa(&__nosave_end)) >> PAGE_SHIFT;
156 return (pfn >= nosave_begin_pfn) && (pfn < nosave_end_pfn);
157}
158
159/**
160 * saveable - Determine whether a page should be cloned or not.
161 * @pfn: The page
162 *
163 * We save a page if it's Reserved, and not in the range of pages
164 * statically defined as 'unsaveable', or if it isn't reserved, and
165 * isn't part of a free chunk of pages.
166 */
167
168static int saveable(struct zone * zone, unsigned long * zone_pfn)
169{
170 unsigned long pfn = *zone_pfn + zone->zone_start_pfn;
171 struct page * page;
172
173 if (!pfn_valid(pfn))
174 return 0;
175
176 page = pfn_to_page(pfn);
177 BUG_ON(PageReserved(page) && PageNosave(page));
178 if (PageNosave(page))
179 return 0;
180 if (PageReserved(page) && pfn_is_nosave(pfn)) {
181 pr_debug("[nosave pfn 0x%lx]", pfn);
182 return 0;
183 }
184 if (PageNosaveFree(page))
185 return 0;
186
187 return 1;
188}
189
190static void count_data_pages(void)
191{
192 struct zone *zone;
193 unsigned long zone_pfn;
194
195 nr_copy_pages = 0;
196
197 for_each_zone (zone) {
198 if (is_highmem(zone))
199 continue;
200 mark_free_pages(zone);
201 for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn)
202 nr_copy_pages += saveable(zone, &zone_pfn);
203 }
204}
205
206static void copy_data_pages(void)
207{
208 struct zone *zone;
209 unsigned long zone_pfn;
210 struct pbe *pbe = pagedir_nosave, *p;
211
212 pr_debug("copy_data_pages(): pages to copy: %d\n", nr_copy_pages);
213 for_each_zone (zone) {
214 if (is_highmem(zone))
215 continue;
216 mark_free_pages(zone);
217 /* This is necessary for swsusp_free() */
218 for_each_pb_page (p, pagedir_nosave)
219 SetPageNosaveFree(virt_to_page(p));
220 for_each_pbe(p, pagedir_nosave)
221 SetPageNosaveFree(virt_to_page(p->address));
222 for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn) {
223 if (saveable(zone, &zone_pfn)) {
224 struct page * page;
225 page = pfn_to_page(zone_pfn + zone->zone_start_pfn);
226 BUG_ON(!pbe);
227 pbe->orig_address = (unsigned long)page_address(page);
228 /* copy_page is not usable for copying task structs. */
229 memcpy((void *)pbe->address, (void *)pbe->orig_address, PAGE_SIZE);
230 pbe = pbe->next;
231 }
232 }
233 }
234 BUG_ON(pbe);
235}
236
237
238/**
239 * free_pagedir - free pages allocated with alloc_pagedir()
240 */
241
242void free_pagedir(struct pbe *pblist)
243{
244 struct pbe *pbe;
245
246 while (pblist) {
247 pbe = (pblist + PB_PAGE_SKIP)->next;
248 ClearPageNosave(virt_to_page(pblist));
249 ClearPageNosaveFree(virt_to_page(pblist));
250 free_page((unsigned long)pblist);
251 pblist = pbe;
252 }
253}
254
255/**
256 * fill_pb_page - Create a list of PBEs on a given memory page
257 */
258
259static inline void fill_pb_page(struct pbe *pbpage)
260{
261 struct pbe *p;
262
263 p = pbpage;
264 pbpage += PB_PAGE_SKIP;
265 do
266 p->next = p + 1;
267 while (++p < pbpage);
268}
269
270/**
271 * create_pbe_list - Create a list of PBEs on top of a given chain
272 * of memory pages allocated with alloc_pagedir()
273 */
274
275void create_pbe_list(struct pbe *pblist, unsigned nr_pages)
276{
277 struct pbe *pbpage, *p;
278 unsigned num = PBES_PER_PAGE;
279
280 for_each_pb_page (pbpage, pblist) {
281 if (num >= nr_pages)
282 break;
283
284 fill_pb_page(pbpage);
285 num += PBES_PER_PAGE;
286 }
287 if (pbpage) {
288 for (num -= PBES_PER_PAGE - 1, p = pbpage; num < nr_pages; p++, num++)
289 p->next = p + 1;
290 p->next = NULL;
291 }
292 pr_debug("create_pbe_list(): initialized %d PBEs\n", num);
293}
294
295static void *alloc_image_page(void)
296{
297 void *res = (void *)get_zeroed_page(GFP_ATOMIC | __GFP_COLD);
298 if (res) {
299 SetPageNosave(virt_to_page(res));
300 SetPageNosaveFree(virt_to_page(res));
301 }
302 return res;
303}
304
305/**
306 * alloc_pagedir - Allocate the page directory.
307 *
308 * First, determine exactly how many pages we need and
309 * allocate them.
310 *
311 * We arrange the pages in a chain: each page is an array of PBES_PER_PAGE
312 * struct pbe elements (pbes) and the last element in the page points
313 * to the next page.
314 *
315 * On each page we set up a list of struct_pbe elements.
316 */
317
318struct pbe * alloc_pagedir(unsigned nr_pages)
319{
320 unsigned num;
321 struct pbe *pblist, *pbe;
322
323 if (!nr_pages)
324 return NULL;
325
326 pr_debug("alloc_pagedir(): nr_pages = %d\n", nr_pages);
327 pblist = (struct pbe *)alloc_image_page();
328 /* FIXME: rewrite this ugly loop */
329 for (pbe = pblist, num = PBES_PER_PAGE; pbe && num < nr_pages;
330 pbe = pbe->next, num += PBES_PER_PAGE) {
331 pbe += PB_PAGE_SKIP;
332 pbe->next = (struct pbe *)alloc_image_page();
333 }
334 if (!pbe) { /* get_zeroed_page() failed */
335 free_pagedir(pblist);
336 pblist = NULL;
337 }
338 return pblist;
339}
340
341/**
342 * Free pages we allocated for suspend. Suspend pages are alocated
343 * before atomic copy, so we need to free them after resume.
344 */
345
346void swsusp_free(void)
347{
348 struct zone *zone;
349 unsigned long zone_pfn;
350
351 for_each_zone(zone) {
352 for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn)
353 if (pfn_valid(zone_pfn + zone->zone_start_pfn)) {
354 struct page * page;
355 page = pfn_to_page(zone_pfn + zone->zone_start_pfn);
356 if (PageNosave(page) && PageNosaveFree(page)) {
357 ClearPageNosave(page);
358 ClearPageNosaveFree(page);
359 free_page((long) page_address(page));
360 }
361 }
362 }
363}
364
365
366/**
367 * enough_free_mem - Make sure we enough free memory to snapshot.
368 *
369 * Returns TRUE or FALSE after checking the number of available
370 * free pages.
371 */
372
373static int enough_free_mem(void)
374{
375 pr_debug("swsusp: available memory: %u pages\n", nr_free_pages());
376 return nr_free_pages() > (nr_copy_pages + PAGES_FOR_IO +
377 nr_copy_pages/PBES_PER_PAGE + !!(nr_copy_pages%PBES_PER_PAGE));
378}
379
380
381static int swsusp_alloc(void)
382{
383 struct pbe * p;
384
385 pagedir_nosave = NULL;
386
387 if (MAX_PBES < nr_copy_pages / PBES_PER_PAGE +
388 !!(nr_copy_pages % PBES_PER_PAGE))
389 return -ENOSPC;
390
391 if (!(pagedir_save = alloc_pagedir(nr_copy_pages))) {
392 printk(KERN_ERR "suspend: Allocating pagedir failed.\n");
393 return -ENOMEM;
394 }
395 create_pbe_list(pagedir_save, nr_copy_pages);
396 pagedir_nosave = pagedir_save;
397
398 for_each_pbe (p, pagedir_save) {
399 p->address = (unsigned long)alloc_image_page();
400 if (!p->address) {
401 printk(KERN_ERR "suspend: Allocating image pages failed.\n");
402 swsusp_free();
403 return -ENOMEM;
404 }
405 }
406
407 return 0;
408}
409
410static int suspend_prepare_image(void)
411{
412 int error;
413
414 pr_debug("swsusp: critical section: \n");
415 if (save_highmem()) {
416 printk(KERN_CRIT "swsusp: Not enough free pages for highmem\n");
417 restore_highmem();
418 return -ENOMEM;
419 }
420
421 drain_local_pages();
422 count_data_pages();
423 printk("swsusp: Need to copy %u pages\n", nr_copy_pages);
424
425 pr_debug("swsusp: pages needed: %u + %lu + %u, free: %u\n",
426 nr_copy_pages,
427 nr_copy_pages/PBES_PER_PAGE + !!(nr_copy_pages%PBES_PER_PAGE),
428 PAGES_FOR_IO, nr_free_pages());
429
430 if (!enough_free_mem()) {
431 printk(KERN_ERR "swsusp: Not enough free memory\n");
432 return -ENOMEM;
433 }
434
435 if (!enough_swap()) {
436 printk(KERN_ERR "swsusp: Not enough free swap\n");
437 return -ENOSPC;
438 }
439
440 error = swsusp_alloc();
441 if (error)
442 return error;
443
444 /* During allocating of suspend pagedir, new cold pages may appear.
445 * Kill them.
446 */
447 drain_local_pages();
448 copy_data_pages();
449
450 /*
451 * End of critical section. From now on, we can write to memory,
452 * but we should not touch disk. This specially means we must _not_
453 * touch swap space! Except we must write out our image of course.
454 */
455
456 printk("swsusp: critical section/: done (%d pages copied)\n", nr_copy_pages );
457 return 0;
458}
459
460
461asmlinkage int swsusp_save(void)
462{
463 return suspend_prepare_image();
464}