[PATCH] Make swsusp avoid memory holes and reserved memory regions on x86_64

On x86_64 machines with more than 2 GB of RAM there are large memory gaps
(with no corresponding kernel virtual addresses) and reserved memory
regions between areas of usable physical RAM.  Moreover, if CONFIG_FLATMEM
is set, they appear within the normal zone.  swsusp should not try to save
them, so the corresponding page structs have to be marked as 'nosave'.

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Cc: Mel Gorman <mel@csn.ul.ie>
Acked-by: Pavel Machek <pavel@ucw.cz>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
Rafael J. Wysocki 2006-09-25 23:32:46 -07:00 committed by Linus Torvalds
parent fb13a28b0f
commit e8eff5ac29
3 changed files with 50 additions and 0 deletions

View file

@ -16,6 +16,7 @@
#include <linux/string.h>
#include <linux/kexec.h>
#include <linux/module.h>
#include <linux/mm.h>
#include <asm/pgtable.h>
#include <asm/page.h>
@ -297,6 +298,53 @@ void __init e820_reserve_resources(void)
}
}
/* Mark pages corresponding to given address range as nosave */
static void __init
e820_mark_nosave_range(unsigned long start, unsigned long end)
{
unsigned long pfn, max_pfn;
if (start >= end)
return;
printk("Nosave address range: %016lx - %016lx\n", start, end);
max_pfn = end >> PAGE_SHIFT;
for (pfn = start >> PAGE_SHIFT; pfn < max_pfn; pfn++)
if (pfn_valid(pfn))
SetPageNosave(pfn_to_page(pfn));
}
/*
* Find the ranges of physical addresses that do not correspond to
* e820 RAM areas and mark the corresponding pages as nosave for software
* suspend and suspend to RAM.
*
* This function requires the e820 map to be sorted and without any
* overlapping entries and assumes the first e820 area to be RAM.
*/
void __init e820_mark_nosave_regions(void)
{
int i;
unsigned long paddr;
paddr = round_down(e820.map[0].addr + e820.map[0].size, PAGE_SIZE);
for (i = 1; i < e820.nr_map; i++) {
struct e820entry *ei = &e820.map[i];
if (paddr < ei->addr)
e820_mark_nosave_range(paddr,
round_up(ei->addr, PAGE_SIZE));
paddr = round_down(ei->addr + ei->size, PAGE_SIZE);
if (ei->type != E820_RAM)
e820_mark_nosave_range(round_up(ei->addr, PAGE_SIZE),
paddr);
if (paddr >= (end_pfn << PAGE_SHIFT))
break;
}
}
/*
* Add a memory region to the kernel e820 map.
*/

View file

@ -689,6 +689,7 @@ void __init setup_arch(char **cmdline_p)
*/
probe_roms();
e820_reserve_resources();
e820_mark_nosave_regions();
request_resource(&iomem_resource, &video_ram_resource);

View file

@ -46,6 +46,7 @@ extern void setup_memory_region(void);
extern void contig_e820_setup(void);
extern unsigned long e820_end_of_ram(void);
extern void e820_reserve_resources(void);
extern void e820_mark_nosave_regions(void);
extern void e820_print_map(char *who);
extern int e820_any_mapped(unsigned long start, unsigned long end, unsigned type);
extern int e820_all_mapped(unsigned long start, unsigned long end, unsigned type);