Commit 940864dd authored by Rafael J. Wysocki's avatar Rafael J. Wysocki Committed by Linus Torvalds

[PATCH] swsusp: Use memory bitmaps during resume

Make swsusp use memory bitmaps to store its internal information during the
resume phase of the suspend-resume cycle.

If the pfns of saveable pages are saved during the suspend phase instead of
the kernel virtual addresses of these pages, we can use them during the resume
phase directly to set the corresponding bits in a memory bitmap.  Then, this
bitmap is used to mark the page frames corresponding to the pages that were
saveable before the suspend (aka "unsafe" page frames).

Next, we allocate as many page frames as needed to store the entire suspend
image and make sure that there will be some extra free "safe" page frames for
the list of PBEs constructed later.  Subsequently, the image is loaded and, if
possible, the data loaded from it are written into their "original" page
frames (ie.  the ones they had occupied before the suspend).

The image data that cannot be written into their "original" page frames are
loaded into "safe" page frames and their "original" kernel virtual addresses,
as well as the addresses of the "safe" pages containing their copies, are
stored in a list of PBEs.  Finally, the list of PBEs is used to copy the
remaining image data into their "original" page frames (this is done
atomically, by the architecture-dependent parts of swsusp).
Signed-off-by: default avatarRafael J. Wysocki <rjw@sisk.pl>
Acked-by: default avatarPavel Machek <pavel@ucw.cz>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent b788db79
...@@ -16,15 +16,6 @@ struct pbe { ...@@ -16,15 +16,6 @@ struct pbe {
struct pbe *next; struct pbe *next;
}; };
#define for_each_pbe(pbe, pblist) \
for (pbe = pblist ; pbe ; pbe = pbe->next)
#define PBES_PER_PAGE (PAGE_SIZE/sizeof(struct pbe))
#define PB_PAGE_SKIP (PBES_PER_PAGE-1)
#define for_each_pb_page(pbe, pblist) \
for (pbe = pblist ; pbe ; pbe = (pbe+PB_PAGE_SKIP)->next)
/* mm/page_alloc.c */ /* mm/page_alloc.c */
extern void drain_local_pages(void); extern void drain_local_pages(void);
extern void mark_free_pages(struct zone *zone); extern void mark_free_pages(struct zone *zone);
......
...@@ -81,16 +81,6 @@ struct snapshot_handle { ...@@ -81,16 +81,6 @@ struct snapshot_handle {
unsigned int prev; /* number of the block of PAGE_SIZE bytes that unsigned int prev; /* number of the block of PAGE_SIZE bytes that
* was the current one previously * was the current one previously
*/ */
struct pbe *pbe; /* PBE that corresponds to 'buffer' */
struct pbe *last_pbe; /* When the image is restored (eg. read
* from disk) we can store some image
* data directly in the page frames
* in which they were before suspend.
* In such a case the PBEs that
* correspond to them will be unused.
* This is the last PBE, so far, that
* does not correspond to such data.
*/
void *buffer; /* address of the block to read from void *buffer; /* address of the block to read from
* or write to * or write to
*/ */
...@@ -113,6 +103,7 @@ extern unsigned int snapshot_additional_pages(struct zone *zone); ...@@ -113,6 +103,7 @@ extern unsigned int snapshot_additional_pages(struct zone *zone);
extern int snapshot_read_next(struct snapshot_handle *handle, size_t count); extern int snapshot_read_next(struct snapshot_handle *handle, size_t count);
extern int snapshot_write_next(struct snapshot_handle *handle, size_t count); extern int snapshot_write_next(struct snapshot_handle *handle, size_t count);
extern int snapshot_image_loaded(struct snapshot_handle *handle); extern int snapshot_image_loaded(struct snapshot_handle *handle);
extern void snapshot_free_unused_memory(struct snapshot_handle *handle);
#define SNAPSHOT_IOC_MAGIC '3' #define SNAPSHOT_IOC_MAGIC '3'
#define SNAPSHOT_FREEZE _IO(SNAPSHOT_IOC_MAGIC, 1) #define SNAPSHOT_FREEZE _IO(SNAPSHOT_IOC_MAGIC, 1)
......
This diff is collapsed.
...@@ -331,8 +331,7 @@ static int enough_swap(unsigned int nr_pages) ...@@ -331,8 +331,7 @@ static int enough_swap(unsigned int nr_pages)
unsigned int free_swap = count_swap_pages(root_swap, 1); unsigned int free_swap = count_swap_pages(root_swap, 1);
pr_debug("swsusp: free swap pages: %u\n", free_swap); pr_debug("swsusp: free swap pages: %u\n", free_swap);
return free_swap > (nr_pages + PAGES_FOR_IO + return free_swap > nr_pages + PAGES_FOR_IO;
(nr_pages + PBES_PER_PAGE - 1) / PBES_PER_PAGE);
} }
/** /**
...@@ -547,6 +546,7 @@ static int load_image(struct swap_map_handle *handle, ...@@ -547,6 +546,7 @@ static int load_image(struct swap_map_handle *handle,
error = err2; error = err2;
if (!error) { if (!error) {
printk("\b\b\b\bdone\n"); printk("\b\b\b\bdone\n");
snapshot_free_unused_memory(snapshot);
if (!snapshot_image_loaded(snapshot)) if (!snapshot_image_loaded(snapshot))
error = -ENODATA; error = -ENODATA;
} }
......
...@@ -193,6 +193,7 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp, ...@@ -193,6 +193,7 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
error = -EPERM; error = -EPERM;
break; break;
} }
snapshot_free_unused_memory(&data->handle);
down(&pm_sem); down(&pm_sem);
pm_prepare_console(); pm_prepare_console();
error = device_suspend(PMSG_FREEZE); error = device_suspend(PMSG_FREEZE);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment