Andi Kleen a écrit :
On Friday 03 February 2006 10:17, Andrew Morton wrote:
It seems that powerpc has gone and changed their implementation of percpu
data so that there is no memory allocated for not-possible CPUs. To save a
bit of RAM.
This means that any code which does
for (i = 0; i < NR_CPUS; i++)
touch(percpudata(i))
will explode on powerpc.
It also explodes since some time on x86-64.
But I added a workaround now (or rather sent one and Linus dropped it)
to point the not possible CPUs to the reference data and not free it.
With that violating that protocol is mostly harmless.
Later the plan was to point it to unmapped data to catch all users.
Maybe you can port the following i386 patch to x86_64 ? (I dont have a x86_64
test machine at this moment)
(This was sent to Andrew Jan 29th, and is included in 2.6.16-rc1-mm5)
Eric
--- a/arch/i386/Kconfig.debug 2006-01-29 22:30:10.000000000 +0100
+++ b/arch/i386/Kconfig.debug 2006-01-29 22:35:54.000000000 +0100
@@ -61,6 +61,18 @@
portion of the kernel code won't be covered by a 2MB TLB anymore.
If in doubt, say "N".
+config DEBUG_INITDATA
+ bool "Read/Write protect kernel init data structures"
+ depends on DEBUG_KERNEL
+ help
+ The init data is normally freed when kernel has booted.
+ Some code may still try to read or write to data in this area.
+ If you say Y here, the kernel will mark this zone as not readable
+ or writeable at all. Buggy code will then fault.
+ This option may have a slight performance impact because a
+ portion of the kernel code won't be covered by a 2MB TLB anymore.
+ If in doubt, say "N".
+
config 4KSTACKS
bool "Use 4Kb + 4Kb for kernel stacks instead of 8Kb" if DEBUG_KERNEL
default y
--- a/arch/i386/mm/init.c 2006-01-25 10:17:24.000000000 +0100
+++ b/arch/i386/mm/init.c 2006-01-29 22:38:53.000000000 +0100
@@ -750,11 +750,18 @@
for (addr = begin; addr < end; addr += PAGE_SIZE) {
ClearPageReserved(virt_to_page(addr));
set_page_count(virt_to_page(addr), 1);
+#ifdef CONFIG_DEBUG_INITDATA
+ change_page_attr(virt_to_page(addr), 1, __pgprot(0));
+#else
memset((void *)addr, 0xcc, PAGE_SIZE);
+#endif
free_page(addr);
totalram_pages++;
}
printk(KERN_INFO "Freeing %s: %ldk freed\n", what, (end - begin) >> 10);
+#ifdef CONFIG_DEBUG_INITDATA
+ global_flush_tlb();
+#endif
}
void free_initmem(void)