summaryrefslogtreecommitdiff
path: root/kernel/power/snapshot.c
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2005-11-08 21:34:39 -0800
committerLinus Torvalds <torvalds@g5.osdl.org>2005-11-09 07:55:52 -0800
commit054bd4c18853f3a3851bd97aa90e11022a69dc42 (patch)
tree6d4aa1416b4837930ed517aa8c6e741ff45e5d9b /kernel/power/snapshot.c
parenta31751e04ea738acc8042e5aa1a825901aa7b97f (diff)
[PATCH] swsusp: reduce code duplication
The changes made by this patch are necessary for the pagedir relocation simplification in the next patch.  Additionally, these changes allow us to drop check_pagedir() and make get_safe_page() be a one-line wrapper around alloc_image_page() (get_safe_page() goes to snapshot.c, because alloc_image_page() is static and it does not make sense to export it). Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Cc: Pavel Machek <pavel@ucw.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.c62
1 files changed, 48 insertions, 14 deletions
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c
index 723f5179883e..96cc3e21e97d 100644
--- a/kernel/power/snapshot.c
+++ b/kernel/power/snapshot.c
@@ -269,9 +269,30 @@ void create_pbe_list(struct pbe *pblist, unsigned int nr_pages)
pr_debug("create_pbe_list(): initialized %d PBEs\n", num);
}
-static void *alloc_image_page(void)
+/**
+ * @safe_needed - on resume, for storing the PBE list and the image,
+ * we can only use memory pages that do not conflict with the pages
+ * which had been used before suspend.
+ *
+ * The unsafe pages are marked with the PG_nosave_free flag
+ *
+ * Allocated but unusable (ie eaten) memory pages should be marked
+ * so that swsusp_free() can release them
+ */
+
+static inline void *alloc_image_page(gfp_t gfp_mask, int safe_needed)
{
- void *res = (void *)get_zeroed_page(GFP_ATOMIC | __GFP_COLD);
+ void *res;
+
+ if (safe_needed)
+ do {
+ res = (void *)get_zeroed_page(gfp_mask);
+ if (res && PageNosaveFree(virt_to_page(res)))
+ /* This is for swsusp_free() */
+ SetPageNosave(virt_to_page(res));
+ } while (res && PageNosaveFree(virt_to_page(res)));
+ else
+ res = (void *)get_zeroed_page(gfp_mask);
if (res) {
SetPageNosave(virt_to_page(res));
SetPageNosaveFree(virt_to_page(res));
@@ -279,6 +300,11 @@ static void *alloc_image_page(void)
return res;
}
+unsigned long get_safe_page(gfp_t gfp_mask)
+{
+ return (unsigned long)alloc_image_page(gfp_mask, 1);
+}
+
/**
* alloc_pagedir - Allocate the page directory.
*
@@ -292,7 +318,7 @@ static void *alloc_image_page(void)
* On each page we set up a list of struct_pbe elements.
*/
-struct pbe *alloc_pagedir(unsigned int nr_pages)
+struct pbe *alloc_pagedir(unsigned int nr_pages, gfp_t gfp_mask, int safe_needed)
{
unsigned int num;
struct pbe *pblist, *pbe;
@@ -301,12 +327,12 @@ struct pbe *alloc_pagedir(unsigned int nr_pages)
return NULL;
pr_debug("alloc_pagedir(): nr_pages = %d\n", nr_pages);
- pblist = alloc_image_page();
+ pblist = alloc_image_page(gfp_mask, safe_needed);
/* FIXME: rewrite this ugly loop */
for (pbe = pblist, num = PBES_PER_PAGE; pbe && num < nr_pages;
pbe = pbe->next, num += PBES_PER_PAGE) {
pbe += PB_PAGE_SKIP;
- pbe->next = alloc_image_page();
+ pbe->next = alloc_image_page(gfp_mask, safe_needed);
}
if (!pbe) { /* get_zeroed_page() failed */
free_pagedir(pblist);
@@ -354,24 +380,32 @@ static int enough_free_mem(unsigned int nr_pages)
(nr_pages + PBES_PER_PAGE - 1) / PBES_PER_PAGE);
}
+int alloc_data_pages(struct pbe *pblist, gfp_t gfp_mask, int safe_needed)
+{
+ struct pbe *p;
+
+ for_each_pbe (p, pblist) {
+ p->address = (unsigned long)alloc_image_page(gfp_mask, safe_needed);
+ if (!p->address)
+ return -ENOMEM;
+ }
+ return 0;
+}
static struct pbe *swsusp_alloc(unsigned int nr_pages)
{
- struct pbe *pblist, *p;
+ struct pbe *pblist;
- if (!(pblist = alloc_pagedir(nr_pages))) {
+ if (!(pblist = alloc_pagedir(nr_pages, GFP_ATOMIC | __GFP_COLD, 0))) {
printk(KERN_ERR "suspend: Allocating pagedir failed.\n");
return NULL;
}
create_pbe_list(pblist, nr_pages);
- for_each_pbe (p, pblist) {
- p->address = (unsigned long)alloc_image_page();
- if (!p->address) {
- printk(KERN_ERR "suspend: Allocating image pages failed.\n");
- swsusp_free();
- return NULL;
- }
+ if (alloc_data_pages(pblist, GFP_ATOMIC | __GFP_COLD, 0)) {
+ printk(KERN_ERR "suspend: Allocating image pages failed.\n");
+ swsusp_free();
+ return NULL;
}
return pblist;