diff options
author | Yinghai Lu <yinghai@kernel.org> | 2010-03-28 22:42:55 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2010-03-29 12:55:33 -0400 |
commit | c967da6a0ba837f762042e931d4afcf72045547c (patch) | |
tree | 3576d2f97e20f3d8d647ea7381f5f99d96220fa2 /arch/x86/kernel/setup.c | |
parent | 596b711ed6b5235f8545680ef38ace00f9898c32 (diff) |
x86: Make sure free_init_pages() frees pages on page boundary
When CONFIG_NO_BOOTMEM=y, it could use memory more effiently, or
in a more compact fashion.
Example:
Allocated new RAMDISK: 00ec2000 - 0248ce57
Move RAMDISK from 000000002ea04000 - 000000002ffcee56 to 00ec2000 - 0248ce56
The new RAMDISK's end is not page aligned.
Last page could be shared with other users.
When free_init_pages are called for initrd or .init, the page
could be freed and we could corrupt other data.
code segment in free_init_pages():
| 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);
| free_page(addr);
| totalram_pages++;
| }
last half page could be used as one whole free page.
So page align the boundaries.
-v2: make the original initramdisk to be aligned, according to
Johannes, otherwise we have the chance to lose one page.
we still need to keep initrd_end not aligned, otherwise it could
confuse decompressor.
-v3: change to WARN_ON instead, suggested by Johannes.
-v4: use PAGE_ALIGN, suggested by Johannes.
We may fix that macro name later to PAGE_ALIGN_UP, and PAGE_ALIGN_DOWN
Add comments about assuming ramdisk start is aligned
in relocate_initrd(), change to re get ramdisk_image instead of save it
to make diff smaller. Add warning for wrong range, suggested by Johannes.
-v6: remove one WARN()
We need to align beginning in free_init_pages()
do not copy more than ramdisk_size, noticed by Johannes
Reported-by: Stanislaw Gruszka <sgruszka@redhat.com>
Tested-by: Stanislaw Gruszka <sgruszka@redhat.com>
Signed-off-by: Yinghai Lu <yinghai@kernel.org>
Acked-by: Johannes Weiner <hannes@cmpxchg.org>
Cc: David Miller <davem@davemloft.net>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
LKML-Reference: <1269830604-26214-3-git-send-email-yinghai@kernel.org>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86/kernel/setup.c')
-rw-r--r-- | arch/x86/kernel/setup.c | 10 |
1 files changed, 6 insertions, 4 deletions
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index 5d7ba1a449bd..d76e18570c60 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c | |||
@@ -314,16 +314,17 @@ static void __init reserve_brk(void) | |||
314 | #define MAX_MAP_CHUNK (NR_FIX_BTMAPS << PAGE_SHIFT) | 314 | #define MAX_MAP_CHUNK (NR_FIX_BTMAPS << PAGE_SHIFT) |
315 | static void __init relocate_initrd(void) | 315 | static void __init relocate_initrd(void) |
316 | { | 316 | { |
317 | 317 | /* Assume only end is not page aligned */ | |
318 | u64 ramdisk_image = boot_params.hdr.ramdisk_image; | 318 | u64 ramdisk_image = boot_params.hdr.ramdisk_image; |
319 | u64 ramdisk_size = boot_params.hdr.ramdisk_size; | 319 | u64 ramdisk_size = boot_params.hdr.ramdisk_size; |
320 | u64 area_size = PAGE_ALIGN(ramdisk_size); | ||
320 | u64 end_of_lowmem = max_low_pfn_mapped << PAGE_SHIFT; | 321 | u64 end_of_lowmem = max_low_pfn_mapped << PAGE_SHIFT; |
321 | u64 ramdisk_here; | 322 | u64 ramdisk_here; |
322 | unsigned long slop, clen, mapaddr; | 323 | unsigned long slop, clen, mapaddr; |
323 | char *p, *q; | 324 | char *p, *q; |
324 | 325 | ||
325 | /* We need to move the initrd down into lowmem */ | 326 | /* We need to move the initrd down into lowmem */ |
326 | ramdisk_here = find_e820_area(0, end_of_lowmem, ramdisk_size, | 327 | ramdisk_here = find_e820_area(0, end_of_lowmem, area_size, |
327 | PAGE_SIZE); | 328 | PAGE_SIZE); |
328 | 329 | ||
329 | if (ramdisk_here == -1ULL) | 330 | if (ramdisk_here == -1ULL) |
@@ -332,7 +333,7 @@ static void __init relocate_initrd(void) | |||
332 | 333 | ||
333 | /* Note: this includes all the lowmem currently occupied by | 334 | /* Note: this includes all the lowmem currently occupied by |
334 | the initrd, we rely on that fact to keep the data intact. */ | 335 | the initrd, we rely on that fact to keep the data intact. */ |
335 | reserve_early(ramdisk_here, ramdisk_here + ramdisk_size, | 336 | reserve_early(ramdisk_here, ramdisk_here + area_size, |
336 | "NEW RAMDISK"); | 337 | "NEW RAMDISK"); |
337 | initrd_start = ramdisk_here + PAGE_OFFSET; | 338 | initrd_start = ramdisk_here + PAGE_OFFSET; |
338 | initrd_end = initrd_start + ramdisk_size; | 339 | initrd_end = initrd_start + ramdisk_size; |
@@ -376,9 +377,10 @@ static void __init relocate_initrd(void) | |||
376 | 377 | ||
377 | static void __init reserve_initrd(void) | 378 | static void __init reserve_initrd(void) |
378 | { | 379 | { |
380 | /* Assume only end is not page aligned */ | ||
379 | u64 ramdisk_image = boot_params.hdr.ramdisk_image; | 381 | u64 ramdisk_image = boot_params.hdr.ramdisk_image; |
380 | u64 ramdisk_size = boot_params.hdr.ramdisk_size; | 382 | u64 ramdisk_size = boot_params.hdr.ramdisk_size; |
381 | u64 ramdisk_end = ramdisk_image + ramdisk_size; | 383 | u64 ramdisk_end = PAGE_ALIGN(ramdisk_image + ramdisk_size); |
382 | u64 end_of_lowmem = max_low_pfn_mapped << PAGE_SHIFT; | 384 | u64 end_of_lowmem = max_low_pfn_mapped << PAGE_SHIFT; |
383 | 385 | ||
384 | if (!boot_params.hdr.type_of_loader || | 386 | if (!boot_params.hdr.type_of_loader || |