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)

Reply via email to