diff options
author | Anton Altaparmakov <aia21@cantab.net> | 2005-10-31 05:06:46 -0500 |
---|---|---|
committer | Anton Altaparmakov <aia21@cantab.net> | 2005-10-31 05:06:46 -0500 |
commit | 1f04c0a24b2f3cfe89c802a24396263623e3512d (patch) | |
tree | d7e2216b6e65b833c0c2b79b478d13ce17dbf296 /kernel/power | |
parent | 07b188ab773e183871e57b33ae37bf635c9f12ba (diff) | |
parent | e2f2e58e7968f8446b1078a20a18bf8ea12b4fbc (diff) |
Merge branch 'master' of /usr/src/ntfs-2.6/
Diffstat (limited to 'kernel/power')
-rw-r--r-- | kernel/power/Makefile | 2 | ||||
-rw-r--r-- | kernel/power/disk.c | 22 | ||||
-rw-r--r-- | kernel/power/main.c | 5 | ||||
-rw-r--r-- | kernel/power/power.h | 17 | ||||
-rw-r--r-- | kernel/power/snapshot.c | 435 | ||||
-rw-r--r-- | kernel/power/swsusp.c | 576 |
6 files changed, 511 insertions, 546 deletions
diff --git a/kernel/power/Makefile b/kernel/power/Makefile index 2f438d0eaa13..c71eb4579c07 100644 --- a/kernel/power/Makefile +++ b/kernel/power/Makefile | |||
@@ -4,7 +4,7 @@ EXTRA_CFLAGS += -DDEBUG | |||
4 | endif | 4 | endif |
5 | 5 | ||
6 | obj-y := main.o process.o console.o pm.o | 6 | obj-y := main.o process.o console.o pm.o |
7 | obj-$(CONFIG_SOFTWARE_SUSPEND) += swsusp.o disk.o | 7 | obj-$(CONFIG_SOFTWARE_SUSPEND) += swsusp.o disk.o snapshot.o |
8 | 8 | ||
9 | obj-$(CONFIG_SUSPEND_SMP) += smp.o | 9 | obj-$(CONFIG_SUSPEND_SMP) += smp.o |
10 | 10 | ||
diff --git a/kernel/power/disk.c b/kernel/power/disk.c index 761956e813f5..027322a564f4 100644 --- a/kernel/power/disk.c +++ b/kernel/power/disk.c | |||
@@ -30,7 +30,6 @@ extern int swsusp_check(void); | |||
30 | extern int swsusp_read(void); | 30 | extern int swsusp_read(void); |
31 | extern void swsusp_close(void); | 31 | extern void swsusp_close(void); |
32 | extern int swsusp_resume(void); | 32 | extern int swsusp_resume(void); |
33 | extern int swsusp_free(void); | ||
34 | 33 | ||
35 | 34 | ||
36 | static int noresume = 0; | 35 | static int noresume = 0; |
@@ -93,10 +92,7 @@ static void free_some_memory(void) | |||
93 | printk("Freeing memory... "); | 92 | printk("Freeing memory... "); |
94 | while ((tmp = shrink_all_memory(10000))) { | 93 | while ((tmp = shrink_all_memory(10000))) { |
95 | pages += tmp; | 94 | pages += tmp; |
96 | printk("\b%c", p[i]); | 95 | printk("\b%c", p[i++ % 4]); |
97 | i++; | ||
98 | if (i > 3) | ||
99 | i = 0; | ||
100 | } | 96 | } |
101 | printk("\bdone (%li pages freed)\n", pages); | 97 | printk("\bdone (%li pages freed)\n", pages); |
102 | } | 98 | } |
@@ -178,13 +174,12 @@ int pm_suspend_disk(void) | |||
178 | goto Done; | 174 | goto Done; |
179 | 175 | ||
180 | if (in_suspend) { | 176 | if (in_suspend) { |
177 | device_resume(); | ||
181 | pr_debug("PM: writing image.\n"); | 178 | pr_debug("PM: writing image.\n"); |
182 | error = swsusp_write(); | 179 | error = swsusp_write(); |
183 | if (!error) | 180 | if (!error) |
184 | power_down(pm_disk_mode); | 181 | power_down(pm_disk_mode); |
185 | else { | 182 | else { |
186 | /* swsusp_write can not fail in device_resume, | ||
187 | no need to do second device_resume */ | ||
188 | swsusp_free(); | 183 | swsusp_free(); |
189 | unprepare_processes(); | 184 | unprepare_processes(); |
190 | return error; | 185 | return error; |
@@ -252,14 +247,17 @@ static int software_resume(void) | |||
252 | 247 | ||
253 | pr_debug("PM: Reading swsusp image.\n"); | 248 | pr_debug("PM: Reading swsusp image.\n"); |
254 | 249 | ||
255 | if ((error = swsusp_read())) | 250 | if ((error = swsusp_read())) { |
256 | goto Cleanup; | 251 | swsusp_free(); |
252 | goto Thaw; | ||
253 | } | ||
257 | 254 | ||
258 | pr_debug("PM: Preparing devices for restore.\n"); | 255 | pr_debug("PM: Preparing devices for restore.\n"); |
259 | 256 | ||
260 | if ((error = device_suspend(PMSG_FREEZE))) { | 257 | if ((error = device_suspend(PMSG_FREEZE))) { |
261 | printk("Some devices failed to suspend\n"); | 258 | printk("Some devices failed to suspend\n"); |
262 | goto Free; | 259 | swsusp_free(); |
260 | goto Thaw; | ||
263 | } | 261 | } |
264 | 262 | ||
265 | mb(); | 263 | mb(); |
@@ -268,9 +266,7 @@ static int software_resume(void) | |||
268 | swsusp_resume(); | 266 | swsusp_resume(); |
269 | pr_debug("PM: Restore failed, recovering.n"); | 267 | pr_debug("PM: Restore failed, recovering.n"); |
270 | device_resume(); | 268 | device_resume(); |
271 | Free: | 269 | Thaw: |
272 | swsusp_free(); | ||
273 | Cleanup: | ||
274 | unprepare_processes(); | 270 | unprepare_processes(); |
275 | Done: | 271 | Done: |
276 | /* For success case, the suspend path will release the lock */ | 272 | /* For success case, the suspend path will release the lock */ |
diff --git a/kernel/power/main.c b/kernel/power/main.c index 22bdc93cc038..18d7d693fbba 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c | |||
@@ -167,6 +167,8 @@ static int enter_state(suspend_state_t state) | |||
167 | { | 167 | { |
168 | int error; | 168 | int error; |
169 | 169 | ||
170 | if (pm_ops->valid && !pm_ops->valid(state)) | ||
171 | return -ENODEV; | ||
170 | if (down_trylock(&pm_sem)) | 172 | if (down_trylock(&pm_sem)) |
171 | return -EBUSY; | 173 | return -EBUSY; |
172 | 174 | ||
@@ -236,7 +238,8 @@ static ssize_t state_show(struct subsystem * subsys, char * buf) | |||
236 | char * s = buf; | 238 | char * s = buf; |
237 | 239 | ||
238 | for (i = 0; i < PM_SUSPEND_MAX; i++) { | 240 | for (i = 0; i < PM_SUSPEND_MAX; i++) { |
239 | if (pm_states[i]) | 241 | if (pm_states[i] && pm_ops && (!pm_ops->valid |
242 | ||(pm_ops->valid && pm_ops->valid(i)))) | ||
240 | s += sprintf(s,"%s ",pm_states[i]); | 243 | s += sprintf(s,"%s ",pm_states[i]); |
241 | } | 244 | } |
242 | s += sprintf(s,"\n"); | 245 | s += sprintf(s,"\n"); |
diff --git a/kernel/power/power.h b/kernel/power/power.h index 6748de23e83c..d4fd96a135ab 100644 --- a/kernel/power/power.h +++ b/kernel/power/power.h | |||
@@ -53,3 +53,20 @@ extern void thaw_processes(void); | |||
53 | 53 | ||
54 | extern int pm_prepare_console(void); | 54 | extern int pm_prepare_console(void); |
55 | extern void pm_restore_console(void); | 55 | extern void pm_restore_console(void); |
56 | |||
57 | |||
58 | /* References to section boundaries */ | ||
59 | extern const void __nosave_begin, __nosave_end; | ||
60 | |||
61 | extern unsigned int nr_copy_pages; | ||
62 | extern suspend_pagedir_t *pagedir_nosave; | ||
63 | extern suspend_pagedir_t *pagedir_save; | ||
64 | |||
65 | extern asmlinkage int swsusp_arch_suspend(void); | ||
66 | extern asmlinkage int swsusp_arch_resume(void); | ||
67 | |||
68 | extern int restore_highmem(void); | ||
69 | extern struct pbe * alloc_pagedir(unsigned nr_pages); | ||
70 | extern void create_pbe_list(struct pbe *pblist, unsigned nr_pages); | ||
71 | extern void swsusp_free(void); | ||
72 | extern int enough_swap(unsigned nr_pages); | ||
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c new file mode 100644 index 000000000000..42a628704398 --- /dev/null +++ b/kernel/power/snapshot.c | |||
@@ -0,0 +1,435 @@ | |||
1 | /* | ||
2 | * linux/kernel/power/snapshot.c | ||
3 | * | ||
4 | * This file provide system snapshot/restore functionality. | ||
5 | * | ||
6 | * Copyright (C) 1998-2005 Pavel Machek <pavel@suse.cz> | ||
7 | * | ||
8 | * This file is released under the GPLv2, and is based on swsusp.c. | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | |||
13 | #include <linux/module.h> | ||
14 | #include <linux/mm.h> | ||
15 | #include <linux/suspend.h> | ||
16 | #include <linux/smp_lock.h> | ||
17 | #include <linux/delay.h> | ||
18 | #include <linux/bitops.h> | ||
19 | #include <linux/spinlock.h> | ||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/pm.h> | ||
22 | #include <linux/device.h> | ||
23 | #include <linux/bootmem.h> | ||
24 | #include <linux/syscalls.h> | ||
25 | #include <linux/console.h> | ||
26 | #include <linux/highmem.h> | ||
27 | |||
28 | #include <asm/uaccess.h> | ||
29 | #include <asm/mmu_context.h> | ||
30 | #include <asm/pgtable.h> | ||
31 | #include <asm/tlbflush.h> | ||
32 | #include <asm/io.h> | ||
33 | |||
34 | #include "power.h" | ||
35 | |||
36 | #ifdef CONFIG_HIGHMEM | ||
37 | struct highmem_page { | ||
38 | char *data; | ||
39 | struct page *page; | ||
40 | struct highmem_page *next; | ||
41 | }; | ||
42 | |||
43 | static struct highmem_page *highmem_copy; | ||
44 | |||
45 | static int save_highmem_zone(struct zone *zone) | ||
46 | { | ||
47 | unsigned long zone_pfn; | ||
48 | mark_free_pages(zone); | ||
49 | for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn) { | ||
50 | struct page *page; | ||
51 | struct highmem_page *save; | ||
52 | void *kaddr; | ||
53 | unsigned long pfn = zone_pfn + zone->zone_start_pfn; | ||
54 | |||
55 | if (!(pfn%1000)) | ||
56 | printk("."); | ||
57 | if (!pfn_valid(pfn)) | ||
58 | continue; | ||
59 | page = pfn_to_page(pfn); | ||
60 | /* | ||
61 | * This condition results from rvmalloc() sans vmalloc_32() | ||
62 | * and architectural memory reservations. This should be | ||
63 | * corrected eventually when the cases giving rise to this | ||
64 | * are better understood. | ||
65 | */ | ||
66 | if (PageReserved(page)) { | ||
67 | printk("highmem reserved page?!\n"); | ||
68 | continue; | ||
69 | } | ||
70 | BUG_ON(PageNosave(page)); | ||
71 | if (PageNosaveFree(page)) | ||
72 | continue; | ||
73 | save = kmalloc(sizeof(struct highmem_page), GFP_ATOMIC); | ||
74 | if (!save) | ||
75 | return -ENOMEM; | ||
76 | save->next = highmem_copy; | ||
77 | save->page = page; | ||
78 | save->data = (void *) get_zeroed_page(GFP_ATOMIC); | ||
79 | if (!save->data) { | ||
80 | kfree(save); | ||
81 | return -ENOMEM; | ||
82 | } | ||
83 | kaddr = kmap_atomic(page, KM_USER0); | ||
84 | memcpy(save->data, kaddr, PAGE_SIZE); | ||
85 | kunmap_atomic(kaddr, KM_USER0); | ||
86 | highmem_copy = save; | ||
87 | } | ||
88 | return 0; | ||
89 | } | ||
90 | |||
91 | |||
92 | static int save_highmem(void) | ||
93 | { | ||
94 | struct zone *zone; | ||
95 | int res = 0; | ||
96 | |||
97 | pr_debug("swsusp: Saving Highmem\n"); | ||
98 | for_each_zone (zone) { | ||
99 | if (is_highmem(zone)) | ||
100 | res = save_highmem_zone(zone); | ||
101 | if (res) | ||
102 | return res; | ||
103 | } | ||
104 | return 0; | ||
105 | } | ||
106 | |||
107 | int restore_highmem(void) | ||
108 | { | ||
109 | printk("swsusp: Restoring Highmem\n"); | ||
110 | while (highmem_copy) { | ||
111 | struct highmem_page *save = highmem_copy; | ||
112 | void *kaddr; | ||
113 | highmem_copy = save->next; | ||
114 | |||
115 | kaddr = kmap_atomic(save->page, KM_USER0); | ||
116 | memcpy(kaddr, save->data, PAGE_SIZE); | ||
117 | kunmap_atomic(kaddr, KM_USER0); | ||
118 | free_page((long) save->data); | ||
119 | kfree(save); | ||
120 | } | ||
121 | return 0; | ||
122 | } | ||
123 | #else | ||
124 | static int save_highmem(void) { return 0; } | ||
125 | int restore_highmem(void) { return 0; } | ||
126 | #endif /* CONFIG_HIGHMEM */ | ||
127 | |||
128 | |||
129 | static int pfn_is_nosave(unsigned long pfn) | ||
130 | { | ||
131 | unsigned long nosave_begin_pfn = __pa(&__nosave_begin) >> PAGE_SHIFT; | ||
132 | unsigned long nosave_end_pfn = PAGE_ALIGN(__pa(&__nosave_end)) >> PAGE_SHIFT; | ||
133 | return (pfn >= nosave_begin_pfn) && (pfn < nosave_end_pfn); | ||
134 | } | ||
135 | |||
136 | /** | ||
137 | * saveable - Determine whether a page should be cloned or not. | ||
138 | * @pfn: The page | ||
139 | * | ||
140 | * We save a page if it's Reserved, and not in the range of pages | ||
141 | * statically defined as 'unsaveable', or if it isn't reserved, and | ||
142 | * isn't part of a free chunk of pages. | ||
143 | */ | ||
144 | |||
145 | static int saveable(struct zone *zone, unsigned long *zone_pfn) | ||
146 | { | ||
147 | unsigned long pfn = *zone_pfn + zone->zone_start_pfn; | ||
148 | struct page *page; | ||
149 | |||
150 | if (!pfn_valid(pfn)) | ||
151 | return 0; | ||
152 | |||
153 | page = pfn_to_page(pfn); | ||
154 | BUG_ON(PageReserved(page) && PageNosave(page)); | ||
155 | if (PageNosave(page)) | ||
156 | return 0; | ||
157 | if (PageReserved(page) && pfn_is_nosave(pfn)) { | ||
158 | pr_debug("[nosave pfn 0x%lx]", pfn); | ||
159 | return 0; | ||
160 | } | ||
161 | if (PageNosaveFree(page)) | ||
162 | return 0; | ||
163 | |||
164 | return 1; | ||
165 | } | ||
166 | |||
167 | static unsigned count_data_pages(void) | ||
168 | { | ||
169 | struct zone *zone; | ||
170 | unsigned long zone_pfn; | ||
171 | unsigned n; | ||
172 | |||
173 | n = 0; | ||
174 | for_each_zone (zone) { | ||
175 | if (is_highmem(zone)) | ||
176 | continue; | ||
177 | mark_free_pages(zone); | ||
178 | for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn) | ||
179 | n += saveable(zone, &zone_pfn); | ||
180 | } | ||
181 | return n; | ||
182 | } | ||
183 | |||
184 | static void copy_data_pages(struct pbe *pblist) | ||
185 | { | ||
186 | struct zone *zone; | ||
187 | unsigned long zone_pfn; | ||
188 | struct pbe *pbe, *p; | ||
189 | |||
190 | pbe = pblist; | ||
191 | for_each_zone (zone) { | ||
192 | if (is_highmem(zone)) | ||
193 | continue; | ||
194 | mark_free_pages(zone); | ||
195 | /* This is necessary for swsusp_free() */ | ||
196 | for_each_pb_page (p, pblist) | ||
197 | SetPageNosaveFree(virt_to_page(p)); | ||
198 | for_each_pbe (p, pblist) | ||
199 | SetPageNosaveFree(virt_to_page(p->address)); | ||
200 | for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn) { | ||
201 | if (saveable(zone, &zone_pfn)) { | ||
202 | struct page *page; | ||
203 | page = pfn_to_page(zone_pfn + zone->zone_start_pfn); | ||
204 | BUG_ON(!pbe); | ||
205 | pbe->orig_address = (unsigned long)page_address(page); | ||
206 | /* copy_page is not usable for copying task structs. */ | ||
207 | memcpy((void *)pbe->address, (void *)pbe->orig_address, PAGE_SIZE); | ||
208 | pbe = pbe->next; | ||
209 | } | ||
210 | } | ||
211 | } | ||
212 | BUG_ON(pbe); | ||
213 | } | ||
214 | |||
215 | |||
216 | /** | ||
217 | * free_pagedir - free pages allocated with alloc_pagedir() | ||
218 | */ | ||
219 | |||
220 | static void free_pagedir(struct pbe *pblist) | ||
221 | { | ||
222 | struct pbe *pbe; | ||
223 | |||
224 | while (pblist) { | ||
225 | pbe = (pblist + PB_PAGE_SKIP)->next; | ||
226 | ClearPageNosave(virt_to_page(pblist)); | ||
227 | ClearPageNosaveFree(virt_to_page(pblist)); | ||
228 | free_page((unsigned long)pblist); | ||
229 | pblist = pbe; | ||
230 | } | ||
231 | } | ||
232 | |||
233 | /** | ||
234 | * fill_pb_page - Create a list of PBEs on a given memory page | ||
235 | */ | ||
236 | |||
237 | static inline void fill_pb_page(struct pbe *pbpage) | ||
238 | { | ||
239 | struct pbe *p; | ||
240 | |||
241 | p = pbpage; | ||
242 | pbpage += PB_PAGE_SKIP; | ||
243 | do | ||
244 | p->next = p + 1; | ||
245 | while (++p < pbpage); | ||
246 | } | ||
247 | |||
248 | /** | ||
249 | * create_pbe_list - Create a list of PBEs on top of a given chain | ||
250 | * of memory pages allocated with alloc_pagedir() | ||
251 | */ | ||
252 | |||
253 | void create_pbe_list(struct pbe *pblist, unsigned nr_pages) | ||
254 | { | ||
255 | struct pbe *pbpage, *p; | ||
256 | unsigned num = PBES_PER_PAGE; | ||
257 | |||
258 | for_each_pb_page (pbpage, pblist) { | ||
259 | if (num >= nr_pages) | ||
260 | break; | ||
261 | |||
262 | fill_pb_page(pbpage); | ||
263 | num += PBES_PER_PAGE; | ||
264 | } | ||
265 | if (pbpage) { | ||
266 | for (num -= PBES_PER_PAGE - 1, p = pbpage; num < nr_pages; p++, num++) | ||
267 | p->next = p + 1; | ||
268 | p->next = NULL; | ||
269 | } | ||
270 | pr_debug("create_pbe_list(): initialized %d PBEs\n", num); | ||
271 | } | ||
272 | |||
273 | static void *alloc_image_page(void) | ||
274 | { | ||
275 | void *res = (void *)get_zeroed_page(GFP_ATOMIC | __GFP_COLD); | ||
276 | if (res) { | ||
277 | SetPageNosave(virt_to_page(res)); | ||
278 | SetPageNosaveFree(virt_to_page(res)); | ||
279 | } | ||
280 | return res; | ||
281 | } | ||
282 | |||
283 | /** | ||
284 | * alloc_pagedir - Allocate the page directory. | ||
285 | * | ||
286 | * First, determine exactly how many pages we need and | ||
287 | * allocate them. | ||
288 | * | ||
289 | * We arrange the pages in a chain: each page is an array of PBES_PER_PAGE | ||
290 | * struct pbe elements (pbes) and the last element in the page points | ||
291 | * to the next page. | ||
292 | * | ||
293 | * On each page we set up a list of struct_pbe elements. | ||
294 | */ | ||
295 | |||
296 | struct pbe *alloc_pagedir(unsigned nr_pages) | ||
297 | { | ||
298 | unsigned num; | ||
299 | struct pbe *pblist, *pbe; | ||
300 | |||
301 | if (!nr_pages) | ||
302 | return NULL; | ||
303 | |||
304 | pr_debug("alloc_pagedir(): nr_pages = %d\n", nr_pages); | ||
305 | pblist = alloc_image_page(); | ||
306 | /* FIXME: rewrite this ugly loop */ | ||
307 | for (pbe = pblist, num = PBES_PER_PAGE; pbe && num < nr_pages; | ||
308 | pbe = pbe->next, num += PBES_PER_PAGE) { | ||
309 | pbe += PB_PAGE_SKIP; | ||
310 | pbe->next = alloc_image_page(); | ||
311 | } | ||
312 | if (!pbe) { /* get_zeroed_page() failed */ | ||
313 | free_pagedir(pblist); | ||
314 | pblist = NULL; | ||
315 | } | ||
316 | return pblist; | ||
317 | } | ||
318 | |||
319 | /** | ||
320 | * Free pages we allocated for suspend. Suspend pages are alocated | ||
321 | * before atomic copy, so we need to free them after resume. | ||
322 | */ | ||
323 | |||
324 | void swsusp_free(void) | ||
325 | { | ||
326 | struct zone *zone; | ||
327 | unsigned long zone_pfn; | ||
328 | |||
329 | for_each_zone(zone) { | ||
330 | for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn) | ||
331 | if (pfn_valid(zone_pfn + zone->zone_start_pfn)) { | ||
332 | struct page * page; | ||
333 | page = pfn_to_page(zone_pfn + zone->zone_start_pfn); | ||
334 | if (PageNosave(page) && PageNosaveFree(page)) { | ||
335 | ClearPageNosave(page); | ||
336 | ClearPageNosaveFree(page); | ||
337 | free_page((long) page_address(page)); | ||
338 | } | ||
339 | } | ||
340 | } | ||
341 | } | ||
342 | |||
343 | |||
344 | /** | ||
345 | * enough_free_mem - Make sure we enough free memory to snapshot. | ||
346 | * | ||
347 | * Returns TRUE or FALSE after checking the number of available | ||
348 | * free pages. | ||
349 | */ | ||
350 | |||
351 | static int enough_free_mem(unsigned nr_pages) | ||
352 | { | ||
353 | pr_debug("swsusp: available memory: %u pages\n", nr_free_pages()); | ||
354 | return nr_free_pages() > (nr_pages + PAGES_FOR_IO + | ||
355 | (nr_pages + PBES_PER_PAGE - 1) / PBES_PER_PAGE); | ||
356 | } | ||
357 | |||
358 | |||
359 | static struct pbe *swsusp_alloc(unsigned nr_pages) | ||
360 | { | ||
361 | struct pbe *pblist, *p; | ||
362 | |||
363 | if (!(pblist = alloc_pagedir(nr_pages))) { | ||
364 | printk(KERN_ERR "suspend: Allocating pagedir failed.\n"); | ||
365 | return NULL; | ||
366 | } | ||
367 | create_pbe_list(pblist, nr_pages); | ||
368 | |||
369 | for_each_pbe (p, pblist) { | ||
370 | p->address = (unsigned long)alloc_image_page(); | ||
371 | if (!p->address) { | ||
372 | printk(KERN_ERR "suspend: Allocating image pages failed.\n"); | ||
373 | swsusp_free(); | ||
374 | return NULL; | ||
375 | } | ||
376 | } | ||
377 | |||
378 | return pblist; | ||
379 | } | ||
380 | |||
381 | asmlinkage int swsusp_save(void) | ||
382 | { | ||
383 | unsigned nr_pages; | ||
384 | |||
385 | pr_debug("swsusp: critical section: \n"); | ||
386 | if (save_highmem()) { | ||
387 | printk(KERN_CRIT "swsusp: Not enough free pages for highmem\n"); | ||
388 | restore_highmem(); | ||
389 | return -ENOMEM; | ||
390 | } | ||
391 | |||
392 | drain_local_pages(); | ||
393 | nr_pages = count_data_pages(); | ||
394 | printk("swsusp: Need to copy %u pages\n", nr_pages); | ||
395 | |||
396 | pr_debug("swsusp: pages needed: %u + %lu + %u, free: %u\n", | ||
397 | nr_pages, | ||
398 | (nr_pages + PBES_PER_PAGE - 1) / PBES_PER_PAGE, | ||
399 | PAGES_FOR_IO, nr_free_pages()); | ||
400 | |||
401 | /* This is needed because of the fixed size of swsusp_info */ | ||
402 | if (MAX_PBES < (nr_pages + PBES_PER_PAGE - 1) / PBES_PER_PAGE) | ||
403 | return -ENOSPC; | ||
404 | |||
405 | if (!enough_free_mem(nr_pages)) { | ||
406 | printk(KERN_ERR "swsusp: Not enough free memory\n"); | ||
407 | return -ENOMEM; | ||
408 | } | ||
409 | |||
410 | if (!enough_swap(nr_pages)) { | ||
411 | printk(KERN_ERR "swsusp: Not enough free swap\n"); | ||
412 | return -ENOSPC; | ||
413 | } | ||
414 | |||
415 | pagedir_nosave = swsusp_alloc(nr_pages); | ||
416 | if (!pagedir_nosave) | ||
417 | return -ENOMEM; | ||
418 | |||
419 | /* During allocating of suspend pagedir, new cold pages may appear. | ||
420 | * Kill them. | ||
421 | */ | ||
422 | drain_local_pages(); | ||
423 | copy_data_pages(pagedir_nosave); | ||
424 | |||
425 | /* | ||
426 | * End of critical section. From now on, we can write to memory, | ||
427 | * but we should not touch disk. This specially means we must _not_ | ||
428 | * touch swap space! Except we must write out our image of course. | ||
429 | */ | ||
430 | |||
431 | nr_copy_pages = nr_pages; | ||
432 | |||
433 | printk("swsusp: critical section/: done (%d pages copied)\n", nr_pages); | ||
434 | return 0; | ||
435 | } | ||
diff --git a/kernel/power/swsusp.c b/kernel/power/swsusp.c index 016504ccfccf..12db1d2ad61f 100644 --- a/kernel/power/swsusp.c +++ b/kernel/power/swsusp.c | |||
@@ -1,11 +1,10 @@ | |||
1 | /* | 1 | /* |
2 | * linux/kernel/power/swsusp.c | 2 | * linux/kernel/power/swsusp.c |
3 | * | 3 | * |
4 | * This file is to realize architecture-independent | 4 | * This file provides code to write suspend image to swap and read it back. |
5 | * machine suspend feature using pretty near only high-level routines | ||
6 | * | 5 | * |
7 | * Copyright (C) 1998-2001 Gabor Kuti <seasons@fornax.hu> | 6 | * Copyright (C) 1998-2001 Gabor Kuti <seasons@fornax.hu> |
8 | * Copyright (C) 1998,2001-2004 Pavel Machek <pavel@suse.cz> | 7 | * Copyright (C) 1998,2001-2005 Pavel Machek <pavel@suse.cz> |
9 | * | 8 | * |
10 | * This file is released under the GPLv2. | 9 | * This file is released under the GPLv2. |
11 | * | 10 | * |
@@ -47,11 +46,7 @@ | |||
47 | #include <linux/utsname.h> | 46 | #include <linux/utsname.h> |
48 | #include <linux/version.h> | 47 | #include <linux/version.h> |
49 | #include <linux/delay.h> | 48 | #include <linux/delay.h> |
50 | #include <linux/reboot.h> | ||
51 | #include <linux/bitops.h> | 49 | #include <linux/bitops.h> |
52 | #include <linux/vt_kern.h> | ||
53 | #include <linux/kbd_kern.h> | ||
54 | #include <linux/keyboard.h> | ||
55 | #include <linux/spinlock.h> | 50 | #include <linux/spinlock.h> |
56 | #include <linux/genhd.h> | 51 | #include <linux/genhd.h> |
57 | #include <linux/kernel.h> | 52 | #include <linux/kernel.h> |
@@ -63,10 +58,8 @@ | |||
63 | #include <linux/swapops.h> | 58 | #include <linux/swapops.h> |
64 | #include <linux/bootmem.h> | 59 | #include <linux/bootmem.h> |
65 | #include <linux/syscalls.h> | 60 | #include <linux/syscalls.h> |
66 | #include <linux/console.h> | ||
67 | #include <linux/highmem.h> | 61 | #include <linux/highmem.h> |
68 | #include <linux/bio.h> | 62 | #include <linux/bio.h> |
69 | #include <linux/mount.h> | ||
70 | 63 | ||
71 | #include <asm/uaccess.h> | 64 | #include <asm/uaccess.h> |
72 | #include <asm/mmu_context.h> | 65 | #include <asm/mmu_context.h> |
@@ -84,16 +77,10 @@ | |||
84 | #define MAXKEY 32 | 77 | #define MAXKEY 32 |
85 | #define MAXIV 32 | 78 | #define MAXIV 32 |
86 | 79 | ||
87 | /* References to section boundaries */ | ||
88 | extern const void __nosave_begin, __nosave_end; | ||
89 | |||
90 | /* Variables to be preserved over suspend */ | ||
91 | static int nr_copy_pages_check; | ||
92 | |||
93 | extern char resume_file[]; | 80 | extern char resume_file[]; |
94 | 81 | ||
95 | /* Local variables that should not be affected by save */ | 82 | /* Local variables that should not be affected by save */ |
96 | static unsigned int nr_copy_pages __nosavedata = 0; | 83 | unsigned int nr_copy_pages __nosavedata = 0; |
97 | 84 | ||
98 | /* Suspend pagedir is allocated before final copy, therefore it | 85 | /* Suspend pagedir is allocated before final copy, therefore it |
99 | must be freed after resume | 86 | must be freed after resume |
@@ -109,7 +96,7 @@ static unsigned int nr_copy_pages __nosavedata = 0; | |||
109 | MMU hardware. | 96 | MMU hardware. |
110 | */ | 97 | */ |
111 | suspend_pagedir_t *pagedir_nosave __nosavedata = NULL; | 98 | suspend_pagedir_t *pagedir_nosave __nosavedata = NULL; |
112 | static suspend_pagedir_t *pagedir_save; | 99 | suspend_pagedir_t *pagedir_save; |
113 | 100 | ||
114 | #define SWSUSP_SIG "S1SUSPEND" | 101 | #define SWSUSP_SIG "S1SUSPEND" |
115 | 102 | ||
@@ -124,12 +111,6 @@ static struct swsusp_header { | |||
124 | static struct swsusp_info swsusp_info; | 111 | static struct swsusp_info swsusp_info; |
125 | 112 | ||
126 | /* | 113 | /* |
127 | * XXX: We try to keep some more pages free so that I/O operations succeed | ||
128 | * without paging. Might this be more? | ||
129 | */ | ||
130 | #define PAGES_FOR_IO 512 | ||
131 | |||
132 | /* | ||
133 | * Saving part... | 114 | * Saving part... |
134 | */ | 115 | */ |
135 | 116 | ||
@@ -552,353 +533,6 @@ static int write_suspend_image(void) | |||
552 | goto Done; | 533 | goto Done; |
553 | } | 534 | } |
554 | 535 | ||
555 | |||
556 | #ifdef CONFIG_HIGHMEM | ||
557 | struct highmem_page { | ||
558 | char *data; | ||
559 | struct page *page; | ||
560 | struct highmem_page *next; | ||
561 | }; | ||
562 | |||
563 | static struct highmem_page *highmem_copy; | ||
564 | |||
565 | static int save_highmem_zone(struct zone *zone) | ||
566 | { | ||
567 | unsigned long zone_pfn; | ||
568 | mark_free_pages(zone); | ||
569 | for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn) { | ||
570 | struct page *page; | ||
571 | struct highmem_page *save; | ||
572 | void *kaddr; | ||
573 | unsigned long pfn = zone_pfn + zone->zone_start_pfn; | ||
574 | |||
575 | if (!(pfn%1000)) | ||
576 | printk("."); | ||
577 | if (!pfn_valid(pfn)) | ||
578 | continue; | ||
579 | page = pfn_to_page(pfn); | ||
580 | /* | ||
581 | * PageReserved results from rvmalloc() sans vmalloc_32() | ||
582 | * and architectural memory reservations. | ||
583 | * | ||
584 | * rvmalloc should not cause this, because all implementations | ||
585 | * appear to always be using vmalloc_32 on architectures with | ||
586 | * highmem. This is a good thing, because we would like to save | ||
587 | * rvmalloc pages. | ||
588 | * | ||
589 | * It appears to be triggered by pages which do not point to | ||
590 | * valid memory (see arch/i386/mm/init.c:one_highpage_init(), | ||
591 | * which sets PageReserved if the page does not point to valid | ||
592 | * RAM. | ||
593 | * | ||
594 | * XXX: must remove usage of PageReserved! | ||
595 | */ | ||
596 | if (PageReserved(page)) | ||
597 | continue; | ||
598 | BUG_ON(PageNosave(page)); | ||
599 | if (PageNosaveFree(page)) | ||
600 | continue; | ||
601 | save = kmalloc(sizeof(struct highmem_page), GFP_ATOMIC); | ||
602 | if (!save) | ||
603 | return -ENOMEM; | ||
604 | save->next = highmem_copy; | ||
605 | save->page = page; | ||
606 | save->data = (void *) get_zeroed_page(GFP_ATOMIC); | ||
607 | if (!save->data) { | ||
608 | kfree(save); | ||
609 | return -ENOMEM; | ||
610 | } | ||
611 | kaddr = kmap_atomic(page, KM_USER0); | ||
612 | memcpy(save->data, kaddr, PAGE_SIZE); | ||
613 | kunmap_atomic(kaddr, KM_USER0); | ||
614 | highmem_copy = save; | ||
615 | } | ||
616 | return 0; | ||
617 | } | ||
618 | #endif /* CONFIG_HIGHMEM */ | ||
619 | |||
620 | |||
621 | static int save_highmem(void) | ||
622 | { | ||
623 | #ifdef CONFIG_HIGHMEM | ||
624 | struct zone *zone; | ||
625 | int res = 0; | ||
626 | |||
627 | pr_debug("swsusp: Saving Highmem\n"); | ||
628 | for_each_zone (zone) { | ||
629 | if (is_highmem(zone)) | ||
630 | res = save_highmem_zone(zone); | ||
631 | if (res) | ||
632 | return res; | ||
633 | } | ||
634 | #endif | ||
635 | return 0; | ||
636 | } | ||
637 | |||
638 | static int restore_highmem(void) | ||
639 | { | ||
640 | #ifdef CONFIG_HIGHMEM | ||
641 | printk("swsusp: Restoring Highmem\n"); | ||
642 | while (highmem_copy) { | ||
643 | struct highmem_page *save = highmem_copy; | ||
644 | void *kaddr; | ||
645 | highmem_copy = save->next; | ||
646 | |||
647 | kaddr = kmap_atomic(save->page, KM_USER0); | ||
648 | memcpy(kaddr, save->data, PAGE_SIZE); | ||
649 | kunmap_atomic(kaddr, KM_USER0); | ||
650 | free_page((long) save->data); | ||
651 | kfree(save); | ||
652 | } | ||
653 | #endif | ||
654 | return 0; | ||
655 | } | ||
656 | |||
657 | |||
658 | static int pfn_is_nosave(unsigned long pfn) | ||
659 | { | ||
660 | unsigned long nosave_begin_pfn = __pa(&__nosave_begin) >> PAGE_SHIFT; | ||
661 | unsigned long nosave_end_pfn = PAGE_ALIGN(__pa(&__nosave_end)) >> PAGE_SHIFT; | ||
662 | return (pfn >= nosave_begin_pfn) && (pfn < nosave_end_pfn); | ||
663 | } | ||
664 | |||
665 | /** | ||
666 | * saveable - Determine whether a page should be cloned or not. | ||
667 | * @pfn: The page | ||
668 | * | ||
669 | * We save a page if it's Reserved, and not in the range of pages | ||
670 | * statically defined as 'unsaveable', or if it isn't reserved, and | ||
671 | * isn't part of a free chunk of pages. | ||
672 | */ | ||
673 | |||
674 | static int saveable(struct zone * zone, unsigned long * zone_pfn) | ||
675 | { | ||
676 | unsigned long pfn = *zone_pfn + zone->zone_start_pfn; | ||
677 | struct page * page; | ||
678 | |||
679 | if (!pfn_valid(pfn)) | ||
680 | return 0; | ||
681 | |||
682 | page = pfn_to_page(pfn); | ||
683 | if (PageNosave(page)) | ||
684 | return 0; | ||
685 | if (pfn_is_nosave(pfn)) { | ||
686 | pr_debug("[nosave pfn 0x%lx]", pfn); | ||
687 | return 0; | ||
688 | } | ||
689 | if (PageNosaveFree(page)) | ||
690 | return 0; | ||
691 | |||
692 | return 1; | ||
693 | } | ||
694 | |||
695 | static void count_data_pages(void) | ||
696 | { | ||
697 | struct zone *zone; | ||
698 | unsigned long zone_pfn; | ||
699 | |||
700 | nr_copy_pages = 0; | ||
701 | |||
702 | for_each_zone (zone) { | ||
703 | if (is_highmem(zone)) | ||
704 | continue; | ||
705 | mark_free_pages(zone); | ||
706 | for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn) | ||
707 | nr_copy_pages += saveable(zone, &zone_pfn); | ||
708 | } | ||
709 | } | ||
710 | |||
711 | |||
712 | static void copy_data_pages(void) | ||
713 | { | ||
714 | struct zone *zone; | ||
715 | unsigned long zone_pfn; | ||
716 | struct pbe * pbe = pagedir_nosave; | ||
717 | |||
718 | pr_debug("copy_data_pages(): pages to copy: %d\n", nr_copy_pages); | ||
719 | for_each_zone (zone) { | ||
720 | if (is_highmem(zone)) | ||
721 | continue; | ||
722 | mark_free_pages(zone); | ||
723 | for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn) { | ||
724 | if (saveable(zone, &zone_pfn)) { | ||
725 | struct page * page; | ||
726 | page = pfn_to_page(zone_pfn + zone->zone_start_pfn); | ||
727 | BUG_ON(!pbe); | ||
728 | pbe->orig_address = (long) page_address(page); | ||
729 | /* copy_page is not usable for copying task structs. */ | ||
730 | memcpy((void *)pbe->address, (void *)pbe->orig_address, PAGE_SIZE); | ||
731 | pbe = pbe->next; | ||
732 | } | ||
733 | } | ||
734 | } | ||
735 | BUG_ON(pbe); | ||
736 | } | ||
737 | |||
738 | |||
739 | /** | ||
740 | * calc_nr - Determine the number of pages needed for a pbe list. | ||
741 | */ | ||
742 | |||
743 | static int calc_nr(int nr_copy) | ||
744 | { | ||
745 | return nr_copy + (nr_copy+PBES_PER_PAGE-2)/(PBES_PER_PAGE-1); | ||
746 | } | ||
747 | |||
748 | /** | ||
749 | * free_pagedir - free pages allocated with alloc_pagedir() | ||
750 | */ | ||
751 | |||
752 | static inline void free_pagedir(struct pbe *pblist) | ||
753 | { | ||
754 | struct pbe *pbe; | ||
755 | |||
756 | while (pblist) { | ||
757 | pbe = (pblist + PB_PAGE_SKIP)->next; | ||
758 | free_page((unsigned long)pblist); | ||
759 | pblist = pbe; | ||
760 | } | ||
761 | } | ||
762 | |||
763 | /** | ||
764 | * fill_pb_page - Create a list of PBEs on a given memory page | ||
765 | */ | ||
766 | |||
767 | static inline void fill_pb_page(struct pbe *pbpage) | ||
768 | { | ||
769 | struct pbe *p; | ||
770 | |||
771 | p = pbpage; | ||
772 | pbpage += PB_PAGE_SKIP; | ||
773 | do | ||
774 | p->next = p + 1; | ||
775 | while (++p < pbpage); | ||
776 | } | ||
777 | |||
778 | /** | ||
779 | * create_pbe_list - Create a list of PBEs on top of a given chain | ||
780 | * of memory pages allocated with alloc_pagedir() | ||
781 | */ | ||
782 | |||
783 | static void create_pbe_list(struct pbe *pblist, unsigned nr_pages) | ||
784 | { | ||
785 | struct pbe *pbpage, *p; | ||
786 | unsigned num = PBES_PER_PAGE; | ||
787 | |||
788 | for_each_pb_page (pbpage, pblist) { | ||
789 | if (num >= nr_pages) | ||
790 | break; | ||
791 | |||
792 | fill_pb_page(pbpage); | ||
793 | num += PBES_PER_PAGE; | ||
794 | } | ||
795 | if (pbpage) { | ||
796 | for (num -= PBES_PER_PAGE - 1, p = pbpage; num < nr_pages; p++, num++) | ||
797 | p->next = p + 1; | ||
798 | p->next = NULL; | ||
799 | } | ||
800 | pr_debug("create_pbe_list(): initialized %d PBEs\n", num); | ||
801 | } | ||
802 | |||
803 | /** | ||
804 | * alloc_pagedir - Allocate the page directory. | ||
805 | * | ||
806 | * First, determine exactly how many pages we need and | ||
807 | * allocate them. | ||
808 | * | ||
809 | * We arrange the pages in a chain: each page is an array of PBES_PER_PAGE | ||
810 | * struct pbe elements (pbes) and the last element in the page points | ||
811 | * to the next page. | ||
812 | * | ||
813 | * On each page we set up a list of struct_pbe elements. | ||
814 | */ | ||
815 | |||
816 | static struct pbe * alloc_pagedir(unsigned nr_pages) | ||
817 | { | ||
818 | unsigned num; | ||
819 | struct pbe *pblist, *pbe; | ||
820 | |||
821 | if (!nr_pages) | ||
822 | return NULL; | ||
823 | |||
824 | pr_debug("alloc_pagedir(): nr_pages = %d\n", nr_pages); | ||
825 | pblist = (struct pbe *)get_zeroed_page(GFP_ATOMIC | __GFP_COLD); | ||
826 | for (pbe = pblist, num = PBES_PER_PAGE; pbe && num < nr_pages; | ||
827 | pbe = pbe->next, num += PBES_PER_PAGE) { | ||
828 | pbe += PB_PAGE_SKIP; | ||
829 | pbe->next = (struct pbe *)get_zeroed_page(GFP_ATOMIC | __GFP_COLD); | ||
830 | } | ||
831 | if (!pbe) { /* get_zeroed_page() failed */ | ||
832 | free_pagedir(pblist); | ||
833 | pblist = NULL; | ||
834 | } | ||
835 | return pblist; | ||
836 | } | ||
837 | |||
838 | /** | ||
839 | * free_image_pages - Free pages allocated for snapshot | ||
840 | */ | ||
841 | |||
842 | static void free_image_pages(void) | ||
843 | { | ||
844 | struct pbe * p; | ||
845 | |||
846 | for_each_pbe (p, pagedir_save) { | ||
847 | if (p->address) { | ||
848 | ClearPageNosave(virt_to_page(p->address)); | ||
849 | free_page(p->address); | ||
850 | p->address = 0; | ||
851 | } | ||
852 | } | ||
853 | } | ||
854 | |||
855 | /** | ||
856 | * alloc_image_pages - Allocate pages for the snapshot. | ||
857 | */ | ||
858 | |||
859 | static int alloc_image_pages(void) | ||
860 | { | ||
861 | struct pbe * p; | ||
862 | |||
863 | for_each_pbe (p, pagedir_save) { | ||
864 | p->address = get_zeroed_page(GFP_ATOMIC | __GFP_COLD); | ||
865 | if (!p->address) | ||
866 | return -ENOMEM; | ||
867 | SetPageNosave(virt_to_page(p->address)); | ||
868 | } | ||
869 | return 0; | ||
870 | } | ||
871 | |||
872 | /* Free pages we allocated for suspend. Suspend pages are alocated | ||
873 | * before atomic copy, so we need to free them after resume. | ||
874 | */ | ||
875 | void swsusp_free(void) | ||
876 | { | ||
877 | BUG_ON(PageNosave(virt_to_page(pagedir_save))); | ||
878 | BUG_ON(PageNosaveFree(virt_to_page(pagedir_save))); | ||
879 | free_image_pages(); | ||
880 | free_pagedir(pagedir_save); | ||
881 | } | ||
882 | |||
883 | |||
884 | /** | ||
885 | * enough_free_mem - Make sure we enough free memory to snapshot. | ||
886 | * | ||
887 | * Returns TRUE or FALSE after checking the number of available | ||
888 | * free pages. | ||
889 | */ | ||
890 | |||
891 | static int enough_free_mem(void) | ||
892 | { | ||
893 | if (nr_free_pages() < (nr_copy_pages + PAGES_FOR_IO)) { | ||
894 | pr_debug("swsusp: Not enough free pages: Have %d\n", | ||
895 | nr_free_pages()); | ||
896 | return 0; | ||
897 | } | ||
898 | return 1; | ||
899 | } | ||
900 | |||
901 | |||
902 | /** | 536 | /** |
903 | * enough_swap - Make sure we have enough swap to save the image. | 537 | * enough_swap - Make sure we have enough swap to save the image. |
904 | * | 538 | * |
@@ -909,87 +543,14 @@ static int enough_free_mem(void) | |||
909 | * We should only consider resume_device. | 543 | * We should only consider resume_device. |
910 | */ | 544 | */ |
911 | 545 | ||
912 | static int enough_swap(void) | 546 | int enough_swap(unsigned nr_pages) |
913 | { | 547 | { |
914 | struct sysinfo i; | 548 | struct sysinfo i; |
915 | 549 | ||
916 | si_swapinfo(&i); | 550 | si_swapinfo(&i); |
917 | if (i.freeswap < (nr_copy_pages + PAGES_FOR_IO)) { | 551 | pr_debug("swsusp: available swap: %lu pages\n", i.freeswap); |
918 | pr_debug("swsusp: Not enough swap. Need %ld\n",i.freeswap); | 552 | return i.freeswap > (nr_pages + PAGES_FOR_IO + |
919 | return 0; | 553 | (nr_pages + PBES_PER_PAGE - 1) / PBES_PER_PAGE); |
920 | } | ||
921 | return 1; | ||
922 | } | ||
923 | |||
924 | static int swsusp_alloc(void) | ||
925 | { | ||
926 | int error; | ||
927 | |||
928 | pagedir_nosave = NULL; | ||
929 | nr_copy_pages = calc_nr(nr_copy_pages); | ||
930 | nr_copy_pages_check = nr_copy_pages; | ||
931 | |||
932 | pr_debug("suspend: (pages needed: %d + %d free: %d)\n", | ||
933 | nr_copy_pages, PAGES_FOR_IO, nr_free_pages()); | ||
934 | |||
935 | if (!enough_free_mem()) | ||
936 | return -ENOMEM; | ||
937 | |||
938 | if (!enough_swap()) | ||
939 | return -ENOSPC; | ||
940 | |||
941 | if (MAX_PBES < nr_copy_pages / PBES_PER_PAGE + | ||
942 | !!(nr_copy_pages % PBES_PER_PAGE)) | ||
943 | return -ENOSPC; | ||
944 | |||
945 | if (!(pagedir_save = alloc_pagedir(nr_copy_pages))) { | ||
946 | printk(KERN_ERR "suspend: Allocating pagedir failed.\n"); | ||
947 | return -ENOMEM; | ||
948 | } | ||
949 | create_pbe_list(pagedir_save, nr_copy_pages); | ||
950 | pagedir_nosave = pagedir_save; | ||
951 | if ((error = alloc_image_pages())) { | ||
952 | printk(KERN_ERR "suspend: Allocating image pages failed.\n"); | ||
953 | swsusp_free(); | ||
954 | return error; | ||
955 | } | ||
956 | |||
957 | return 0; | ||
958 | } | ||
959 | |||
960 | static int suspend_prepare_image(void) | ||
961 | { | ||
962 | int error; | ||
963 | |||
964 | pr_debug("swsusp: critical section: \n"); | ||
965 | if (save_highmem()) { | ||
966 | printk(KERN_CRIT "Suspend machine: Not enough free pages for highmem\n"); | ||
967 | restore_highmem(); | ||
968 | return -ENOMEM; | ||
969 | } | ||
970 | |||
971 | drain_local_pages(); | ||
972 | count_data_pages(); | ||
973 | printk("swsusp: Need to copy %u pages\n", nr_copy_pages); | ||
974 | |||
975 | error = swsusp_alloc(); | ||
976 | if (error) | ||
977 | return error; | ||
978 | |||
979 | /* During allocating of suspend pagedir, new cold pages may appear. | ||
980 | * Kill them. | ||
981 | */ | ||
982 | drain_local_pages(); | ||
983 | copy_data_pages(); | ||
984 | |||
985 | /* | ||
986 | * End of critical section. From now on, we can write to memory, | ||
987 | * but we should not touch disk. This specially means we must _not_ | ||
988 | * touch swap space! Except we must write out our image of course. | ||
989 | */ | ||
990 | |||
991 | printk("swsusp: critical section/: done (%d pages copied)\n", nr_copy_pages ); | ||
992 | return 0; | ||
993 | } | 554 | } |
994 | 555 | ||
995 | 556 | ||
@@ -1001,7 +562,7 @@ static int suspend_prepare_image(void) | |||
1001 | int swsusp_write(void) | 562 | int swsusp_write(void) |
1002 | { | 563 | { |
1003 | int error; | 564 | int error; |
1004 | device_resume(); | 565 | |
1005 | lock_swapdevices(); | 566 | lock_swapdevices(); |
1006 | error = write_suspend_image(); | 567 | error = write_suspend_image(); |
1007 | /* This will unlock ignored swap devices since writing is finished */ | 568 | /* This will unlock ignored swap devices since writing is finished */ |
@@ -1011,14 +572,6 @@ int swsusp_write(void) | |||
1011 | } | 572 | } |
1012 | 573 | ||
1013 | 574 | ||
1014 | extern asmlinkage int swsusp_arch_suspend(void); | ||
1015 | extern asmlinkage int swsusp_arch_resume(void); | ||
1016 | |||
1017 | |||
1018 | asmlinkage int swsusp_save(void) | ||
1019 | { | ||
1020 | return suspend_prepare_image(); | ||
1021 | } | ||
1022 | 575 | ||
1023 | int swsusp_suspend(void) | 576 | int swsusp_suspend(void) |
1024 | { | 577 | { |
@@ -1050,7 +603,6 @@ int swsusp_suspend(void) | |||
1050 | printk(KERN_ERR "Error %d suspending\n", error); | 603 | printk(KERN_ERR "Error %d suspending\n", error); |
1051 | /* Restore control flow magically appears here */ | 604 | /* Restore control flow magically appears here */ |
1052 | restore_processor_state(); | 605 | restore_processor_state(); |
1053 | BUG_ON (nr_copy_pages_check != nr_copy_pages); | ||
1054 | restore_highmem(); | 606 | restore_highmem(); |
1055 | device_power_up(); | 607 | device_power_up(); |
1056 | local_irq_enable(); | 608 | local_irq_enable(); |
@@ -1070,6 +622,11 @@ int swsusp_resume(void) | |||
1070 | * execution continues at place where swsusp_arch_suspend was called | 622 | * execution continues at place where swsusp_arch_suspend was called |
1071 | */ | 623 | */ |
1072 | BUG_ON(!error); | 624 | BUG_ON(!error); |
625 | /* The only reason why swsusp_arch_resume() can fail is memory being | ||
626 | * very tight, so we have to free it as soon as we can to avoid | ||
627 | * subsequent failures | ||
628 | */ | ||
629 | swsusp_free(); | ||
1073 | restore_processor_state(); | 630 | restore_processor_state(); |
1074 | restore_highmem(); | 631 | restore_highmem(); |
1075 | touch_softlockup_watchdog(); | 632 | touch_softlockup_watchdog(); |
@@ -1085,54 +642,28 @@ int swsusp_resume(void) | |||
1085 | * | 642 | * |
1086 | * We don't know which pages are usable until we allocate them. | 643 | * We don't know which pages are usable until we allocate them. |
1087 | * | 644 | * |
1088 | * Allocated but unusable (ie eaten) memory pages are linked together | 645 | * Allocated but unusable (ie eaten) memory pages are marked so that |
1089 | * to create a list, so that we can free them easily | 646 | * swsusp_free() can release them |
1090 | * | ||
1091 | * We could have used a type other than (void *) | ||
1092 | * for this purpose, but ... | ||
1093 | */ | 647 | */ |
1094 | static void **eaten_memory = NULL; | ||
1095 | |||
1096 | static inline void eat_page(void *page) | ||
1097 | { | ||
1098 | void **c; | ||
1099 | |||
1100 | c = eaten_memory; | ||
1101 | eaten_memory = page; | ||
1102 | *eaten_memory = c; | ||
1103 | } | ||
1104 | 648 | ||
1105 | unsigned long get_usable_page(gfp_t gfp_mask) | 649 | unsigned long get_safe_page(gfp_t gfp_mask) |
1106 | { | 650 | { |
1107 | unsigned long m; | 651 | unsigned long m; |
1108 | 652 | ||
1109 | m = get_zeroed_page(gfp_mask); | 653 | do { |
1110 | while (!PageNosaveFree(virt_to_page(m))) { | ||
1111 | eat_page((void *)m); | ||
1112 | m = get_zeroed_page(gfp_mask); | 654 | m = get_zeroed_page(gfp_mask); |
1113 | if (!m) | 655 | if (m && PageNosaveFree(virt_to_page(m))) |
1114 | break; | 656 | /* This is for swsusp_free() */ |
657 | SetPageNosave(virt_to_page(m)); | ||
658 | } while (m && PageNosaveFree(virt_to_page(m))); | ||
659 | if (m) { | ||
660 | /* This is for swsusp_free() */ | ||
661 | SetPageNosave(virt_to_page(m)); | ||
662 | SetPageNosaveFree(virt_to_page(m)); | ||
1115 | } | 663 | } |
1116 | return m; | 664 | return m; |
1117 | } | 665 | } |
1118 | 666 | ||
1119 | void free_eaten_memory(void) | ||
1120 | { | ||
1121 | unsigned long m; | ||
1122 | void **c; | ||
1123 | int i = 0; | ||
1124 | |||
1125 | c = eaten_memory; | ||
1126 | while (c) { | ||
1127 | m = (unsigned long)c; | ||
1128 | c = *c; | ||
1129 | free_page(m); | ||
1130 | i++; | ||
1131 | } | ||
1132 | eaten_memory = NULL; | ||
1133 | pr_debug("swsusp: %d unused pages freed\n", i); | ||
1134 | } | ||
1135 | |||
1136 | /** | 667 | /** |
1137 | * check_pagedir - We ensure here that pages that the PBEs point to | 668 | * check_pagedir - We ensure here that pages that the PBEs point to |
1138 | * won't collide with pages where we're going to restore from the loaded | 669 | * won't collide with pages where we're going to restore from the loaded |
@@ -1150,7 +681,7 @@ static int check_pagedir(struct pbe *pblist) | |||
1150 | p->address = 0UL; | 681 | p->address = 0UL; |
1151 | 682 | ||
1152 | for_each_pbe (p, pblist) { | 683 | for_each_pbe (p, pblist) { |
1153 | p->address = get_usable_page(GFP_ATOMIC); | 684 | p->address = get_safe_page(GFP_ATOMIC); |
1154 | if (!p->address) | 685 | if (!p->address) |
1155 | return -ENOMEM; | 686 | return -ENOMEM; |
1156 | } | 687 | } |
@@ -1169,7 +700,7 @@ static struct pbe * swsusp_pagedir_relocate(struct pbe *pblist) | |||
1169 | unsigned long zone_pfn; | 700 | unsigned long zone_pfn; |
1170 | struct pbe *pbpage, *tail, *p; | 701 | struct pbe *pbpage, *tail, *p; |
1171 | void *m; | 702 | void *m; |
1172 | int rel = 0, error = 0; | 703 | int rel = 0; |
1173 | 704 | ||
1174 | if (!pblist) /* a sanity check */ | 705 | if (!pblist) /* a sanity check */ |
1175 | return NULL; | 706 | return NULL; |
@@ -1177,41 +708,37 @@ static struct pbe * swsusp_pagedir_relocate(struct pbe *pblist) | |||
1177 | pr_debug("swsusp: Relocating pagedir (%lu pages to check)\n", | 708 | pr_debug("swsusp: Relocating pagedir (%lu pages to check)\n", |
1178 | swsusp_info.pagedir_pages); | 709 | swsusp_info.pagedir_pages); |
1179 | 710 | ||
1180 | /* Set page flags */ | 711 | /* Clear page flags */ |
1181 | 712 | ||
1182 | for_each_zone (zone) { | 713 | for_each_zone (zone) { |
1183 | for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn) | 714 | for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn) |
1184 | SetPageNosaveFree(pfn_to_page(zone_pfn + | 715 | if (pfn_valid(zone_pfn + zone->zone_start_pfn)) |
716 | ClearPageNosaveFree(pfn_to_page(zone_pfn + | ||
1185 | zone->zone_start_pfn)); | 717 | zone->zone_start_pfn)); |
1186 | } | 718 | } |
1187 | 719 | ||
1188 | /* Clear orig addresses */ | 720 | /* Mark orig addresses */ |
1189 | 721 | ||
1190 | for_each_pbe (p, pblist) | 722 | for_each_pbe (p, pblist) |
1191 | ClearPageNosaveFree(virt_to_page(p->orig_address)); | 723 | SetPageNosaveFree(virt_to_page(p->orig_address)); |
1192 | 724 | ||
1193 | tail = pblist + PB_PAGE_SKIP; | 725 | tail = pblist + PB_PAGE_SKIP; |
1194 | 726 | ||
1195 | /* Relocate colliding pages */ | 727 | /* Relocate colliding pages */ |
1196 | 728 | ||
1197 | for_each_pb_page (pbpage, pblist) { | 729 | for_each_pb_page (pbpage, pblist) { |
1198 | if (!PageNosaveFree(virt_to_page((unsigned long)pbpage))) { | 730 | if (PageNosaveFree(virt_to_page((unsigned long)pbpage))) { |
1199 | m = (void *)get_usable_page(GFP_ATOMIC | __GFP_COLD); | 731 | m = (void *)get_safe_page(GFP_ATOMIC | __GFP_COLD); |
1200 | if (!m) { | 732 | if (!m) |
1201 | error = -ENOMEM; | 733 | return NULL; |
1202 | break; | ||
1203 | } | ||
1204 | memcpy(m, (void *)pbpage, PAGE_SIZE); | 734 | memcpy(m, (void *)pbpage, PAGE_SIZE); |
1205 | if (pbpage == pblist) | 735 | if (pbpage == pblist) |
1206 | pblist = (struct pbe *)m; | 736 | pblist = (struct pbe *)m; |
1207 | else | 737 | else |
1208 | tail->next = (struct pbe *)m; | 738 | tail->next = (struct pbe *)m; |
1209 | |||
1210 | eat_page((void *)pbpage); | ||
1211 | pbpage = (struct pbe *)m; | 739 | pbpage = (struct pbe *)m; |
1212 | 740 | ||
1213 | /* We have to link the PBEs again */ | 741 | /* We have to link the PBEs again */ |
1214 | |||
1215 | for (p = pbpage; p < pbpage + PB_PAGE_SKIP; p++) | 742 | for (p = pbpage; p < pbpage + PB_PAGE_SKIP; p++) |
1216 | if (p->next) /* needed to save the end */ | 743 | if (p->next) /* needed to save the end */ |
1217 | p->next = p + 1; | 744 | p->next = p + 1; |
@@ -1221,15 +748,13 @@ static struct pbe * swsusp_pagedir_relocate(struct pbe *pblist) | |||
1221 | tail = pbpage + PB_PAGE_SKIP; | 748 | tail = pbpage + PB_PAGE_SKIP; |
1222 | } | 749 | } |
1223 | 750 | ||
1224 | if (error) { | 751 | /* This is for swsusp_free() */ |
1225 | printk("\nswsusp: Out of memory\n\n"); | 752 | for_each_pb_page (pbpage, pblist) { |
1226 | free_pagedir(pblist); | 753 | SetPageNosave(virt_to_page(pbpage)); |
1227 | free_eaten_memory(); | 754 | SetPageNosaveFree(virt_to_page(pbpage)); |
1228 | pblist = NULL; | 755 | } |
1229 | /* Is this even worth handling? It should never ever happen, and we | 756 | |
1230 | have just lost user's state, anyway... */ | 757 | printk("swsusp: Relocated %d pages\n", rel); |
1231 | } else | ||
1232 | printk("swsusp: Relocated %d pages\n", rel); | ||
1233 | 758 | ||
1234 | return pblist; | 759 | return pblist; |
1235 | } | 760 | } |
@@ -1447,9 +972,7 @@ static int read_pagedir(struct pbe *pblist) | |||
1447 | break; | 972 | break; |
1448 | } | 973 | } |
1449 | 974 | ||
1450 | if (error) | 975 | if (!error) |
1451 | free_pagedir(pblist); | ||
1452 | else | ||
1453 | BUG_ON(i != swsusp_info.pagedir_pages); | 976 | BUG_ON(i != swsusp_info.pagedir_pages); |
1454 | 977 | ||
1455 | return error; | 978 | return error; |
@@ -1492,15 +1015,6 @@ static int read_suspend_image(void) | |||
1492 | if (!error) | 1015 | if (!error) |
1493 | error = data_read(pagedir_nosave); | 1016 | error = data_read(pagedir_nosave); |
1494 | 1017 | ||
1495 | if (error) { /* We fail cleanly */ | ||
1496 | free_eaten_memory(); | ||
1497 | for_each_pbe (p, pagedir_nosave) | ||
1498 | if (p->address) { | ||
1499 | free_page(p->address); | ||
1500 | p->address = 0UL; | ||
1501 | } | ||
1502 | free_pagedir(pagedir_nosave); | ||
1503 | } | ||
1504 | return error; | 1018 | return error; |
1505 | } | 1019 | } |
1506 | 1020 | ||