Commit 7088a5c0 authored by Rafael J. Wysocki's avatar Rafael J. Wysocki Committed by Linus Torvalds

[PATCH] swsusp: introduce the swap map structure

This patch introduces the swap map structure that can be used by swsusp for
keeping tracks of data pages written to the swap.   The structure itself is
described in a comment within the patch.

The overall idea is to reduce the amount of metadata written to the swap and
to write and read the image pages sequentially, in a file-alike way.  This
makes the swap-handling part of swsusp fairly independent of its
snapshot-handling part and will hopefully allow us to completely separate
these two parts in the future.

This patch is needed to remove the suspend image size limit imposed by the
limited size of the swsusp_info structure, which is essential for x86-64
systems with more than 512 MB of RAM.
Signed-off-by: default avatarRafael J. Wysocki <rjw@sisk.pl>
Acked-by: default avatarPavel Machek <pavel@suse.cz>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent f2d97f02
......@@ -14,11 +14,7 @@
typedef struct pbe {
unsigned long address; /* address of the copy */
unsigned long orig_address; /* original address of page */
swp_entry_t swap_address;
struct pbe *next; /* also used as scratch space at
* end of page (see link, diskpage)
*/
struct pbe *next;
} suspend_pagedir_t;
#define for_each_pbe(pbe, pblist) \
......
......@@ -25,9 +25,9 @@
extern suspend_disk_method_t pm_disk_mode;
extern int swsusp_suspend(void);
extern int swsusp_write(void);
extern int swsusp_write(struct pbe *pblist, unsigned int nr_pages);
extern int swsusp_check(void);
extern int swsusp_read(void);
extern int swsusp_read(struct pbe **pblist_ptr);
extern void swsusp_close(void);
extern int swsusp_resume(void);
......@@ -176,7 +176,7 @@ int pm_suspend_disk(void)
if (in_suspend) {
device_resume();
pr_debug("PM: writing image.\n");
error = swsusp_write();
error = swsusp_write(pagedir_nosave, nr_copy_pages);
if (!error)
power_down(pm_disk_mode);
else {
......@@ -247,7 +247,7 @@ static int software_resume(void)
pr_debug("PM: Reading swsusp image.\n");
if ((error = swsusp_read())) {
if ((error = swsusp_read(&pagedir_nosave))) {
swsusp_free();
goto Thaw;
}
......
......@@ -9,19 +9,14 @@
#define SUSPEND_CONSOLE (MAX_NR_CONSOLES-1)
#endif
#define MAX_PBES ((PAGE_SIZE - sizeof(struct new_utsname) \
- 4 - 3*sizeof(unsigned long) - sizeof(int) \
- sizeof(void *)) / sizeof(swp_entry_t))
struct swsusp_info {
struct new_utsname uts;
u32 version_code;
unsigned long num_physpages;
int cpus;
unsigned long image_pages;
unsigned long pagedir_pages;
suspend_pagedir_t * suspend_pagedir;
swp_entry_t pagedir[MAX_PBES];
unsigned long pages;
swp_entry_t start;
} __attribute__((aligned(PAGE_SIZE)));
......@@ -67,6 +62,8 @@ extern asmlinkage int swsusp_arch_resume(void);
extern void free_pagedir(struct pbe *pblist);
extern struct pbe *alloc_pagedir(unsigned nr_pages, gfp_t gfp_mask, int safe_needed);
extern void create_pbe_list(struct pbe *pblist, unsigned nr_pages);
extern void swsusp_free(void);
extern int alloc_data_pages(struct pbe *pblist, gfp_t gfp_mask, int safe_needed);
extern unsigned int snapshot_nr_pages(void);
extern struct pbe *snapshot_pblist(void);
extern void snapshot_pblist_set(struct pbe *pblist);
......@@ -33,6 +33,9 @@
#include "power.h"
struct pbe *pagedir_nosave;
unsigned int nr_copy_pages;
#ifdef CONFIG_HIGHMEM
struct highmem_page {
char *data;
......@@ -244,7 +247,7 @@ static inline void fill_pb_page(struct pbe *pbpage)
* of memory pages allocated with alloc_pagedir()
*/
void create_pbe_list(struct pbe *pblist, unsigned int nr_pages)
static inline void create_pbe_list(struct pbe *pblist, unsigned int nr_pages)
{
struct pbe *pbpage, *p;
unsigned int num = PBES_PER_PAGE;
......@@ -261,7 +264,6 @@ void create_pbe_list(struct pbe *pblist, unsigned int nr_pages)
p->next = p + 1;
p->next = NULL;
}
pr_debug("create_pbe_list(): initialized %d PBEs\n", num);
}
/**
......@@ -332,7 +334,8 @@ struct pbe *alloc_pagedir(unsigned int nr_pages, gfp_t gfp_mask, int safe_needed
if (!pbe) { /* get_zeroed_page() failed */
free_pagedir(pblist);
pblist = NULL;
}
} else
create_pbe_list(pblist, nr_pages);
return pblist;
}
......@@ -395,7 +398,6 @@ static struct pbe *swsusp_alloc(unsigned int nr_pages)
printk(KERN_ERR "suspend: Allocating pagedir failed.\n");
return NULL;
}
create_pbe_list(pblist, nr_pages);
if (alloc_data_pages(pblist, GFP_ATOMIC | __GFP_COLD, 0)) {
printk(KERN_ERR "suspend: Allocating image pages failed.\n");
......@@ -421,10 +423,6 @@ asmlinkage int swsusp_save(void)
(nr_pages + PBES_PER_PAGE - 1) / PBES_PER_PAGE,
PAGES_FOR_IO, nr_free_pages());
/* This is needed because of the fixed size of swsusp_info */
if (MAX_PBES < (nr_pages + PBES_PER_PAGE - 1) / PBES_PER_PAGE)
return -ENOSPC;
if (!enough_free_mem(nr_pages)) {
printk(KERN_ERR "swsusp: Not enough free memory\n");
return -ENOMEM;
......
This diff is collapsed.
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