[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:
parent
fb13a28b0f
commit
e8eff5ac29
3 changed files with 50 additions and 0 deletions
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue