Initrd memory is freed late and page-wise, so allocate full pages and not share the last one with somebody else. Also add a warning and a fixup in free_init_pages() to catch unaligned ranges more explicitely in the future. Signed-off-by: Yinghai Lu <yinghai@xxxxxxxxxx> Signed-off-by: Johannes Weiner <hannes@xxxxxxxxxxx> --- arch/x86/kernel/head32.c | 8 +++++++- arch/x86/kernel/head64.c | 8 +++++++- arch/x86/kernel/setup.c | 14 ++++++++++---- arch/x86/mm/init.c | 12 ++++++++---- 4 files changed, 32 insertions(+), 10 deletions(-) On Sat, Mar 27, 2010 at 06:58:38PM -0700, Yinghai Lu wrote: > please check. I am really fed up with you replying to one point of an email and skipping over five others. So here is my version of the patch, the maintainers can choose. Differences: o only align the allocation area size, no need to also copy alignment bits in relocate_initrd() o keep the alignment fixup in free_init_pages() out of line and self-contained diff --git a/arch/x86/kernel/head32.c b/arch/x86/kernel/head32.c index adedeef..086392a 100644 --- a/arch/x86/kernel/head32.c +++ b/arch/x86/kernel/head32.c @@ -46,7 +46,13 @@ void __init i386_start_kernel(void) if (boot_params.hdr.type_of_loader && boot_params.hdr.ramdisk_image) { u64 ramdisk_image = boot_params.hdr.ramdisk_image; u64 ramdisk_size = boot_params.hdr.ramdisk_size; - u64 ramdisk_end = ramdisk_image + ramdisk_size; + u64 ramdisk_end; + /* + * Initrd memory is freed late and page-wise, so make + * sure not to share a page with other users. Assume + * start is aligned. + */ + ramdisk_end = PAGE_ALIGN(ramdisk_image + ramdisk_size); reserve_early(ramdisk_image, ramdisk_end, "RAMDISK"); } #endif diff --git a/arch/x86/kernel/head64.c b/arch/x86/kernel/head64.c index b5a9896..b2c2321 100644 --- a/arch/x86/kernel/head64.c +++ b/arch/x86/kernel/head64.c @@ -105,7 +105,13 @@ void __init x86_64_start_reservations(char *real_mode_data) if (boot_params.hdr.type_of_loader && boot_params.hdr.ramdisk_image) { unsigned long ramdisk_image = boot_params.hdr.ramdisk_image; unsigned long ramdisk_size = boot_params.hdr.ramdisk_size; - unsigned long ramdisk_end = ramdisk_image + ramdisk_size; + unsigned long ramdisk_end; + /* + * Initrd memory is freed late and page-wise, so make + * sure not to share a page with other users. Assume + * start is aligned. + */ + ramdisk_end = PAGE_ALIGN(ramdisk_image + ramdisk_size); reserve_early(ramdisk_image, ramdisk_end, "RAMDISK"); } #endif diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index 5d7ba1a..f5bde5f 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -318,12 +318,18 @@ static void __init relocate_initrd(void) u64 ramdisk_image = boot_params.hdr.ramdisk_image; u64 ramdisk_size = boot_params.hdr.ramdisk_size; u64 end_of_lowmem = max_low_pfn_mapped << PAGE_SHIFT; - u64 ramdisk_here; + u64 ramdisk_here, area_size; unsigned long slop, clen, mapaddr; char *p, *q; + /* + * Initrd memory is freed late and page-wise, so make sure not + * to share a page with other users. Assume start is aligned. + */ + area_size = PAGE_ALIGN(ramdisk_size); + /* We need to move the initrd down into lowmem */ - ramdisk_here = find_e820_area(0, end_of_lowmem, ramdisk_size, + ramdisk_here = find_e820_area(0, end_of_lowmem, area_size, PAGE_SIZE); if (ramdisk_here == -1ULL) @@ -332,7 +338,7 @@ static void __init relocate_initrd(void) /* Note: this includes all the lowmem currently occupied by the initrd, we rely on that fact to keep the data intact. */ - reserve_early(ramdisk_here, ramdisk_here + ramdisk_size, + reserve_early(ramdisk_here, ramdisk_here + area_size, "NEW RAMDISK"); initrd_start = ramdisk_here + PAGE_OFFSET; initrd_end = initrd_start + ramdisk_size; @@ -378,7 +384,7 @@ static void __init reserve_initrd(void) { u64 ramdisk_image = boot_params.hdr.ramdisk_image; u64 ramdisk_size = boot_params.hdr.ramdisk_size; - u64 ramdisk_end = ramdisk_image + ramdisk_size; + u64 ramdisk_end = PAGE_ALIGN(ramdisk_image + ramdisk_size); u64 end_of_lowmem = max_low_pfn_mapped << PAGE_SHIFT; if (!boot_params.hdr.type_of_loader || diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c index e71c5cb..4b28d5e 100644 --- a/arch/x86/mm/init.c +++ b/arch/x86/mm/init.c @@ -333,6 +333,11 @@ void free_init_pages(char *what, unsigned long begin, unsigned long end) { unsigned long addr = begin; + if (WARN_ON(addr & ~PAGE_MASK || end & ~PAGE_MASK)) { + addr = PAGE_ALIGN(addr); + end &= PAGE_MASK; + } + if (addr >= end) return; @@ -355,11 +360,10 @@ void free_init_pages(char *what, unsigned long begin, unsigned long end) printk(KERN_INFO "Freeing %s: %luk freed\n", what, (end - begin) >> 10); - for (; addr < end; addr += PAGE_SIZE) { + for (; addr != end; addr += PAGE_SIZE) { ClearPageReserved(virt_to_page(addr)); init_page_count(virt_to_page(addr)); - memset((void *)(addr & ~(PAGE_SIZE-1)), - POISON_FREE_INITMEM, PAGE_SIZE); + memset((void *)addr, POISON_FREE_INITMEM, PAGE_SIZE); free_page(addr); totalram_pages++; } @@ -376,6 +380,6 @@ void free_initmem(void) #ifdef CONFIG_BLK_DEV_INITRD void free_initrd_mem(unsigned long start, unsigned long end) { - free_init_pages("initrd memory", start, end); + free_init_pages("initrd memory", start, PAGE_ALIGN(end)); } #endif -- 1.7.0.2 -- To unsubscribe from this list: send the line "unsubscribe linux-arch" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html