From: "Rafael J. Wysocki" <rjw@sisk.pl>
To: linux-kernel@vger.kernel.org
Cc: Pavel Machek <pavel@suse.cz>
Subject: Re: [PATCH 2/3] swsusp: move snapshot-handling functions to snapshot.c
Date: Mon, 31 Oct 2005 20:36:36 +0100 [thread overview]
Message-ID: <200510312036.36335.rjw@sisk.pl> (raw)
In-Reply-To: <20051030195254.GA1729@openzaurus.ucw.cz>
Hi,
On Sunday, 30 of October 2005 20:52, Pavel Machek wrote:
> Hi!
>
> > This patch moves the snapshot-handling functions remaining in swsusp.c
> > to snapshot.c (ie. it moves the code without changing the functionality).
> >
>
> I'm sorry, but I acked this one too quickly. I'd prefer to keep "relocate" code where
> it is, and define "must not collide" as a part of interface. That will keep snapshot.c
> smaller/simpler,
Speaking of simplifications and having seen your code I hope you will agree with
the appended patch against vanilla 2.6.14-git3 (it reduces the duplication of code,
and replaces swsusp_pagedir_relocate with a simpler mechanism).
Greetings,
Rafael
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
kernel/power/power.h | 6 +-
kernel/power/snapshot.c | 121 +++++++++++++++++++++++++++++++++--------
kernel/power/swsusp.c | 139 ++----------------------------------------------
3 files changed, 109 insertions(+), 157 deletions(-)
Index: linux-2.6.14-git3/kernel/power/power.h
===================================================================
--- linux-2.6.14-git3.orig/kernel/power/power.h 2005-10-31 20:27:30.000000000 +0100
+++ linux-2.6.14-git3/kernel/power/power.h 2005-10-31 20:29:31.000000000 +0100
@@ -66,7 +66,11 @@
extern asmlinkage int swsusp_arch_resume(void);
extern int restore_highmem(void);
-extern struct pbe * alloc_pagedir(unsigned nr_pages);
+extern void free_pagedir(struct pbe *pblist);
+extern struct pbe *alloc_pagedir(unsigned nr_pages, int need_safe);
extern void create_pbe_list(struct pbe *pblist, unsigned nr_pages);
+extern int alloc_data_pages(struct pbe *pblist, int need_safe);
extern void swsusp_free(void);
extern int enough_swap(unsigned nr_pages);
+extern void mark_unsafe_pages(struct pbe *pblist);
+extern void copy_page_backup_list(struct pbe *dst, struct pbe *src);
Index: linux-2.6.14-git3/kernel/power/snapshot.c
===================================================================
--- linux-2.6.14-git3.orig/kernel/power/snapshot.c 2005-10-31 20:27:30.000000000 +0100
+++ linux-2.6.14-git3/kernel/power/snapshot.c 2005-10-31 20:29:31.000000000 +0100
@@ -212,12 +212,44 @@
BUG_ON(pbe);
}
+/**
+ * @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 help of SetPageNosaveFree()
+ * in mark_unsafe_pages()
+ *
+ * Allocated but unusable (ie eaten) memory pages should be marked
+ * so that swsusp_free() can release them
+ */
+
+static inline unsigned long snapshot_get_page(gfp_t gfp_mask, int safe_needed)
+{
+ unsigned long m;
+
+ if (safe_needed)
+ do {
+ m = get_zeroed_page(gfp_mask);
+ if (m && PageNosaveFree(virt_to_page(m)))
+ /* This is for swsusp_free() */
+ SetPageNosave(virt_to_page(m));
+ } while (m && PageNosaveFree(virt_to_page(m)));
+ else
+ m = get_zeroed_page(gfp_mask);
+ if (m) {
+ /* This is for swsusp_free() */
+ SetPageNosave(virt_to_page(m));
+ SetPageNosaveFree(virt_to_page(m));
+ }
+ return m;
+}
/**
* free_pagedir - free pages allocated with alloc_pagedir()
*/
-static void free_pagedir(struct pbe *pblist)
+void free_pagedir(struct pbe *pblist)
{
struct pbe *pbe;
@@ -270,22 +302,14 @@
pr_debug("create_pbe_list(): initialized %d PBEs\n", num);
}
-static void *alloc_image_page(void)
+static inline void *alloc_image_page(int safe_needed)
{
- void *res = (void *)get_zeroed_page(GFP_ATOMIC | __GFP_COLD);
- if (res) {
- SetPageNosave(virt_to_page(res));
- SetPageNosaveFree(virt_to_page(res));
- }
- return res;
+ return (void *)snapshot_get_page(GFP_ATOMIC | __GFP_COLD, safe_needed);
}
/**
* alloc_pagedir - Allocate the page directory.
*
- * First, determine exactly how many pages we need and
- * allocate them.
- *
* We arrange the pages in a chain: each page is an array of PBES_PER_PAGE
* struct pbe elements (pbes) and the last element in the page points
* to the next page.
@@ -293,7 +317,7 @@
* On each page we set up a list of struct_pbe elements.
*/
-struct pbe *alloc_pagedir(unsigned nr_pages)
+struct pbe *alloc_pagedir(unsigned nr_pages, int safe_needed)
{
unsigned num;
struct pbe *pblist, *pbe;
@@ -302,12 +326,12 @@
return NULL;
pr_debug("alloc_pagedir(): nr_pages = %d\n", nr_pages);
- pblist = alloc_image_page();
+ pblist = alloc_image_page(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(safe_needed);
}
if (!pbe) { /* get_zeroed_page() failed */
free_pagedir(pblist);
@@ -316,6 +340,18 @@
return pblist;
}
+int alloc_data_pages(struct pbe *pblist, int safe_needed)
+{
+ struct pbe *p;
+
+ for_each_pbe (p, pblist) {
+ p->address = (unsigned long)alloc_image_page(safe_needed);
+ if (!p->address)
+ return -ENOMEM;
+ }
+ return 0;
+}
+
/**
* Free pages we allocated for suspend. Suspend pages are alocated
* before atomic copy, so we need to free them after resume.
@@ -355,24 +391,20 @@
(nr_pages + PBES_PER_PAGE - 1) / PBES_PER_PAGE);
}
-
static struct pbe *swsusp_alloc(unsigned nr_pages)
{
- struct pbe *pblist, *p;
+ struct pbe *pblist;
- if (!(pblist = alloc_pagedir(nr_pages))) {
+ if (!(pblist = alloc_pagedir(nr_pages, 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, 0)) {
+ printk(KERN_ERR "suspend: Allocating image pages failed.\n");
+ swsusp_free();
+ return NULL;
}
return pblist;
@@ -433,3 +465,44 @@
printk("swsusp: critical section/: done (%d pages copied)\n", nr_pages);
return 0;
}
+
+/* Resume-related functions */
+
+void mark_unsafe_pages(struct pbe *pblist)
+{
+ struct zone *zone;
+ unsigned long zone_pfn;
+ struct pbe *p;
+
+ if (!pblist) /* a sanity check */
+ return;
+
+ /* Clear page flags */
+ for_each_zone (zone) {
+ for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn)
+ if (pfn_valid(zone_pfn + zone->zone_start_pfn))
+ ClearPageNosaveFree(pfn_to_page(zone_pfn +
+ zone->zone_start_pfn));
+ }
+
+ /* Mark orig addresses */
+ for_each_pbe (p, pblist)
+ SetPageNosaveFree(virt_to_page(p->orig_address));
+
+}
+
+void copy_page_backup_list(struct pbe *dst, struct pbe *src)
+{
+ /* We assume both lists contain the same number of elements */
+ while (src) {
+ dst->orig_address = src->orig_address;
+ dst->swap_address = src->swap_address;
+ dst = dst->next;
+ src = src->next;
+ }
+}
+
+unsigned long get_safe_page(gfp_t gfp_mask)
+{
+ return (unsigned long)snapshot_get_page(gfp_mask, 1);
+}
Index: linux-2.6.14-git3/kernel/power/swsusp.c
===================================================================
--- linux-2.6.14-git3.orig/kernel/power/swsusp.c 2005-10-31 20:27:30.000000000 +0100
+++ linux-2.6.14-git3/kernel/power/swsusp.c 2005-10-31 20:29:31.000000000 +0100
@@ -635,130 +635,6 @@
return error;
}
-/**
- * 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.
- *
- * We don't know which pages are usable until we allocate them.
- *
- * Allocated but unusable (ie eaten) memory pages are marked so that
- * swsusp_free() can release them
- */
-
-unsigned long get_safe_page(gfp_t gfp_mask)
-{
- unsigned long m;
-
- do {
- m = get_zeroed_page(gfp_mask);
- if (m && PageNosaveFree(virt_to_page(m)))
- /* This is for swsusp_free() */
- SetPageNosave(virt_to_page(m));
- } while (m && PageNosaveFree(virt_to_page(m)));
- if (m) {
- /* This is for swsusp_free() */
- SetPageNosave(virt_to_page(m));
- SetPageNosaveFree(virt_to_page(m));
- }
- return m;
-}
-
-/**
- * check_pagedir - We ensure here that pages that the PBEs point to
- * won't collide with pages where we're going to restore from the loaded
- * pages later
- */
-
-static int check_pagedir(struct pbe *pblist)
-{
- struct pbe *p;
-
- /* This is necessary, so that we can free allocated pages
- * in case of failure
- */
- for_each_pbe (p, pblist)
- p->address = 0UL;
-
- for_each_pbe (p, pblist) {
- p->address = get_safe_page(GFP_ATOMIC);
- if (!p->address)
- return -ENOMEM;
- }
- return 0;
-}
-
-/**
- * swsusp_pagedir_relocate - It is possible, that some memory pages
- * occupied by the list of PBEs collide with pages where we're going to
- * restore from the loaded pages later. We relocate them here.
- */
-
-static struct pbe * swsusp_pagedir_relocate(struct pbe *pblist)
-{
- struct zone *zone;
- unsigned long zone_pfn;
- struct pbe *pbpage, *tail, *p;
- void *m;
- int rel = 0;
-
- if (!pblist) /* a sanity check */
- return NULL;
-
- pr_debug("swsusp: Relocating pagedir (%lu pages to check)\n",
- swsusp_info.pagedir_pages);
-
- /* Clear page flags */
-
- for_each_zone (zone) {
- for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn)
- if (pfn_valid(zone_pfn + zone->zone_start_pfn))
- ClearPageNosaveFree(pfn_to_page(zone_pfn +
- zone->zone_start_pfn));
- }
-
- /* Mark orig addresses */
-
- for_each_pbe (p, pblist)
- SetPageNosaveFree(virt_to_page(p->orig_address));
-
- tail = pblist + PB_PAGE_SKIP;
-
- /* Relocate colliding pages */
-
- for_each_pb_page (pbpage, pblist) {
- if (PageNosaveFree(virt_to_page((unsigned long)pbpage))) {
- m = (void *)get_safe_page(GFP_ATOMIC | __GFP_COLD);
- if (!m)
- return NULL;
- memcpy(m, (void *)pbpage, PAGE_SIZE);
- if (pbpage == pblist)
- pblist = (struct pbe *)m;
- else
- tail->next = (struct pbe *)m;
- pbpage = (struct pbe *)m;
-
- /* We have to link the PBEs again */
- for (p = pbpage; p < pbpage + PB_PAGE_SKIP; p++)
- if (p->next) /* needed to save the end */
- p->next = p + 1;
-
- rel++;
- }
- tail = pbpage + PB_PAGE_SKIP;
- }
-
- /* This is for swsusp_free() */
- for_each_pb_page (pbpage, pblist) {
- SetPageNosave(virt_to_page(pbpage));
- SetPageNosaveFree(virt_to_page(pbpage));
- }
-
- printk("swsusp: Relocated %d pages\n", rel);
-
- return pblist;
-}
-
/*
* Using bio to read from swap.
* This code requires a bit more work than just using buffer heads
@@ -905,9 +781,6 @@
/**
* data_read - Read image pages from swap.
- *
- * You do not need to check for overlaps, check_pagedir()
- * already did that.
*/
static int data_read(struct pbe *pblist)
@@ -997,20 +870,22 @@
int error = 0;
struct pbe *p;
- if (!(p = alloc_pagedir(nr_copy_pages)))
+ if (!(p = alloc_pagedir(nr_copy_pages, 0)))
return -ENOMEM;
if ((error = read_pagedir(p)))
return error;
-
create_pbe_list(p, nr_copy_pages);
-
- if (!(pagedir_nosave = swsusp_pagedir_relocate(p)))
+ mark_unsafe_pages(p);
+ if (!(pagedir_nosave = alloc_pagedir(nr_copy_pages, 1)))
return -ENOMEM;
+ create_pbe_list(pagedir_nosave, nr_copy_pages);
+ copy_page_backup_list(pagedir_nosave, p);
+ free_pagedir(p);
/* Allocate memory for the image and read the data from swap */
- error = check_pagedir(pagedir_nosave);
+ error = alloc_data_pages(pagedir_nosave, 1);
if (!error)
error = data_read(pagedir_nosave);
next prev parent reply other threads:[~2005-10-31 19:36 UTC|newest]
Thread overview: 25+ messages / expand[flat|nested] mbox.gz Atom feed top
2005-10-30 15:37 [PATCH 0/3] swsusp: code separation continued Rafael J. Wysocki
2005-10-30 15:40 ` [PATCH 1/3] swsusp: rework swsusp_suspend Rafael J. Wysocki
2005-10-30 17:54 ` Ingo Oeser
2005-10-30 21:18 ` Rafael J. Wysocki
2005-10-30 15:44 ` [PATCH 2/3] swsusp: move snapshot-handling functions to snapshot.c Rafael J. Wysocki
2005-10-30 19:52 ` Pavel Machek
2005-10-30 21:16 ` Rafael J. Wysocki
2005-10-30 21:28 ` Pavel Machek
2005-10-30 22:37 ` Rafael J. Wysocki
2005-10-30 23:04 ` Pavel Machek
2005-10-31 0:35 ` Rafael J. Wysocki
2005-10-31 21:59 ` Pavel Machek
2005-11-01 18:29 ` Rafael J. Wysocki
2005-11-01 21:04 ` Pavel Machek
2005-11-01 23:53 ` Rafael J. Wysocki
2005-11-02 21:08 ` Pavel Machek
2005-10-31 19:36 ` Rafael J. Wysocki [this message]
2005-10-31 22:02 ` Pavel Machek
2005-11-01 12:57 ` Rafael J. Wysocki
2005-11-01 17:33 ` [PATCH 1/2] swsusp: reduce code duplication (was: Re: [PATCH 2/3] swsusp: move snapshot-handling functions to snapshot.c) Rafael J. Wysocki
2005-11-01 17:37 ` [PATCH 2/2] swsusp: simplify pagedir relocation Rafael J. Wysocki
2005-11-01 21:11 ` Pavel Machek
2005-11-01 23:15 ` Rafael J. Wysocki
2005-11-01 21:09 ` [PATCH 1/2] swsusp: reduce code duplication (was: Re: [PATCH 2/3] swsusp: move snapshot-handling functions to snapshot.c) Pavel Machek
2005-10-30 15:48 ` [PATCH 3/3] swsusp: move swap check out of swsusp_suspend Rafael J. Wysocki
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=200510312036.36335.rjw@sisk.pl \
--to=rjw@sisk.pl \
--cc=linux-kernel@vger.kernel.org \
--cc=pavel@suse.cz \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.