/* Suspend pagedir is allocated before final copy, therefore it
must be freed after resume
- Warning: this is evil. There are actually two pagedirs at time of
- resume. One is "pagedir_save", which is empty frame allocated at
- time of suspend, that must be freed. Second is "pagedir_nosave",
- allocated at time of resume, that travels through memory not to
- collide with anything.
-
Warning: this is even more evil than it seems. Pagedirs this file
talks about are completely different from page directories used by
MMU hardware.
*/
suspend_pagedir_t *pagedir_nosave __nosavedata = NULL;
-suspend_pagedir_t *pagedir_save;
#define SWSUSP_SIG "S1SUSPEND"
static unsigned short swapfile_used[MAX_SWAPFILES];
static unsigned short root_swap;
-static int write_page(unsigned long addr, swp_entry_t * loc);
-static int bio_read_page(pgoff_t page_off, void * page);
+static int write_page(unsigned long addr, swp_entry_t *loc);
+static int bio_read_page(pgoff_t page_off, void *page);
static u8 key_iv[MAXKEY+MAXIV];
* This is a partial improvement, since we will at least return other
* errors, though we need to eventually fix the damn code.
*/
-static int write_page(unsigned long addr, swp_entry_t * loc)
+static int write_page(unsigned long addr, swp_entry_t *loc)
{
swp_entry_t entry;
int error = 0;
static void data_free(void)
{
swp_entry_t entry;
- struct pbe * p;
+ struct pbe *p;
- for_each_pbe(p, pagedir_nosave) {
+ for_each_pbe (p, pagedir_nosave) {
entry = p->swap_address;
if (entry.val)
swap_free(entry);
static int write_pagedir(void)
{
int error = 0;
- unsigned n = 0;
- struct pbe * pbe;
+ unsigned int n = 0;
+ struct pbe *pbe;
printk( "Writing pagedir...");
for_each_pb_page (pbe, pagedir_nosave) {
* We should only consider resume_device.
*/
-int enough_swap(unsigned nr_pages)
+int enough_swap(unsigned int nr_pages)
{
struct sysinfo i;
}
/**
- * 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.
+ * mark_unsafe_pages - mark the pages that cannot be used for storing
+ * the image during resume, because they conflict with the pages that
+ * had been used before suspend
*/
-static struct pbe * swsusp_pagedir_relocate(struct pbe *pblist)
+static void mark_unsafe_pages(struct pbe *pblist)
{
struct zone *zone;
unsigned long zone_pfn;
- struct pbe *pbpage, *tail, *p;
- void *m;
- int rel = 0;
+ struct pbe *p;
if (!pblist) /* a sanity check */
- return NULL;
-
- pr_debug("swsusp: Relocating pagedir (%lu pages to check)\n",
- swsusp_info.pagedir_pages);
+ 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 +
+ 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));
+static 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;
}
-
- printk("swsusp: Relocated %d pages\n", rel);
-
- return pblist;
}
/*
static atomic_t io_done = ATOMIC_INIT(0);
-static int end_io(struct bio * bio, unsigned int num, int err)
+static int end_io(struct bio *bio, unsigned int num, int err)
{
if (!test_bit(BIO_UPTODATE, &bio->bi_flags))
panic("I/O error reading memory image");
return 0;
}
-static struct block_device * resume_bdev;
+static struct block_device *resume_bdev;
/**
* submit - submit BIO request.
* Then submit it and wait.
*/
-static int submit(int rw, pgoff_t page_off, void * page)
+static int submit(int rw, pgoff_t page_off, void *page)
{
int error = 0;
- struct bio * bio;
+ struct bio *bio;
bio = bio_alloc(GFP_ATOMIC, 1);
if (!bio)
return error;
}
-static int bio_read_page(pgoff_t page_off, void * page)
+static int bio_read_page(pgoff_t page_off, void *page)
{
return submit(READ, page_off, page);
}
-static int bio_write_page(pgoff_t page_off, void * page)
+static int bio_write_page(pgoff_t page_off, void *page)
{
return submit(WRITE, page_off, page);
}
* I really don't think that it's foolproof but more than nothing..
*/
-static const char * sanity_check(void)
+static const char *sanity_check(void)
{
dump_info();
if (swsusp_info.version_code != LINUX_VERSION_CODE)
static int check_header(void)
{
- const char * reason = NULL;
+ const char *reason = NULL;
int error;
if ((error = bio_read_page(swp_offset(swsusp_header.swsusp_info), &swsusp_info)))
static int data_read(struct pbe *pblist)
{
- struct pbe * p;
+ struct pbe *p;
int error = 0;
int i = 0;
int mod = swsusp_info.image_pages / 100;
static int read_pagedir(struct pbe *pblist)
{
struct pbe *pbpage, *p;
- unsigned i = 0;
+ unsigned int i = 0;
int error;
if (!pblist)
int error = 0;
struct pbe *p;
- if (!(p = alloc_pagedir(nr_copy_pages)))
+ if (!(p = alloc_pagedir(nr_copy_pages, GFP_ATOMIC, 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);
+ pagedir_nosave = alloc_pagedir(nr_copy_pages, GFP_ATOMIC, 1);
+ if (pagedir_nosave) {
+ create_pbe_list(pagedir_nosave, nr_copy_pages);
+ copy_page_backup_list(pagedir_nosave, p);
+ }
+ free_pagedir(p);
+ if (!pagedir_nosave)
return -ENOMEM;
/* Allocate memory for the image and read the data from swap */
- error = check_pagedir(pagedir_nosave);
+ error = alloc_data_pages(pagedir_nosave, GFP_ATOMIC, 1);
if (!error)
error = data_read(pagedir_nosave);