Patches contributed by Eötvös Lorand University


commit 3bf8f5a92cd4b04e3f1e162a1b4b99759a882b5d
Author: Ingo Molnar <mingo@elte.hu>
Date:   Sat Feb 9 00:15:06 2008 +0100

    x86: fix pgtable_t build breakage
    
    Commit 2f569afd9ced9ebec9a6eb3dbf6f83429be0a7b4 ("CONFIG_HIGHPTE vs.
    sub-page page tables") caused some build breakage due to pgtable_t only
    getting declared in the CONFIG_X86_PAE case.
    
    Move the declaration outside the PAE section.
    
    Signed-off-by: Ingo Molnar <mingo@elte.hu>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

diff --git a/include/asm-x86/page_32.h b/include/asm-x86/page_32.h
index ba715d9798b0..984998a30741 100644
--- a/include/asm-x86/page_32.h
+++ b/include/asm-x86/page_32.h
@@ -50,11 +50,13 @@ typedef unsigned long	phys_addr_t;
 typedef union { pteval_t pte, pte_low; } pte_t;
 typedef pte_t boot_pte_t;
 
-typedef struct page *pgtable_t;
-
 #endif	/* __ASSEMBLY__ */
 #endif	/* CONFIG_X86_PAE */
 
+#ifndef __ASSEMBLY__
+typedef struct page *pgtable_t;
+#endif
+
 #ifdef CONFIG_HUGETLB_PAGE
 #define HAVE_ARCH_HUGETLB_UNMAPPED_AREA
 #endif

commit 3adbefee6fd58a061b2bf1df4f3769701860fc62
Author: Ingo Molnar <mingo@elte.hu>
Date:   Tue Feb 5 17:57:39 2008 -0800

    SLUB: fix checkpatch warnings
    
    fix checkpatch --file mm/slub.c errors and warnings.
    
     $ q-code-quality-compare
                                          errors   lines of code   errors/KLOC
     mm/slub.c      [before]                  22            4204           5.2
     mm/slub.c      [after]                    0            4210             0
    
    no code changed:
    
        text    data     bss     dec     hex filename
       22195    8634     136   30965    78f5 slub.o.before
       22195    8634     136   30965    78f5 slub.o.after
    
       md5:
         93cdfbec2d6450622163c590e1064358  slub.o.before.asm
         93cdfbec2d6450622163c590e1064358  slub.o.after.asm
    
    [clameter: rediffed against Pekka's cleanup patch, omitted
    moves of the name of a function to the start of line]
    Signed-off-by: Ingo Molnar <mingo@elte.hu>
    Signed-off-by: Christoph Lameter <clameter@sgi.com>

diff --git a/mm/slub.c b/mm/slub.c
index bccfb6a17864..e2989ae243b5 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -719,9 +719,10 @@ static int check_object(struct kmem_cache *s, struct page *page,
 			endobject, red, s->inuse - s->objsize))
 			return 0;
 	} else {
-		if ((s->flags & SLAB_POISON) && s->objsize < s->inuse)
-			check_bytes_and_report(s, page, p, "Alignment padding", endobject,
-				POISON_INUSE, s->inuse - s->objsize);
+		if ((s->flags & SLAB_POISON) && s->objsize < s->inuse) {
+			check_bytes_and_report(s, page, p, "Alignment padding",
+				endobject, POISON_INUSE, s->inuse - s->objsize);
+		}
 	}
 
 	if (s->flags & SLAB_POISON) {
@@ -928,11 +929,10 @@ static int free_debug_processing(struct kmem_cache *s, struct page *page,
 		return 0;
 
 	if (unlikely(s != page->slab)) {
-		if (!PageSlab(page))
+		if (!PageSlab(page)) {
 			slab_err(s, page, "Attempt to free object(0x%p) "
 				"outside of slab", object);
-		else
-		if (!page->slab) {
+		} else if (!page->slab) {
 			printk(KERN_ERR
 				"SLUB <none>: no slab for object 0x%p.\n",
 						object);
@@ -1041,7 +1041,7 @@ static unsigned long kmem_cache_flags(unsigned long objsize,
 		 */
 		if (slub_debug && (!slub_debug_slabs ||
 		    strncmp(slub_debug_slabs, name,
-		    	strlen(slub_debug_slabs)) == 0))
+			strlen(slub_debug_slabs)) == 0))
 				flags |= slub_debug;
 	}
 
@@ -1330,8 +1330,8 @@ static struct page *get_any_partial(struct kmem_cache *s, gfp_t flags)
 			get_cycles() % 1024 > s->remote_node_defrag_ratio)
 		return NULL;
 
-	zonelist = &NODE_DATA(slab_node(current->mempolicy))
-					->node_zonelists[gfp_zone(flags)];
+	zonelist = &NODE_DATA(
+		slab_node(current->mempolicy))->node_zonelists[gfp_zone(flags)];
 	for (z = zonelist->zones; *z; z++) {
 		struct kmem_cache_node *n;
 
@@ -2589,7 +2589,8 @@ static noinline struct kmem_cache *dma_kmalloc_cache(int index, gfp_t flags)
 		goto unlock_out;
 
 	realsize = kmalloc_caches[index].objsize;
-	text = kasprintf(flags & ~SLUB_DMA, "kmalloc_dma-%d", (unsigned int)realsize),
+	text = kasprintf(flags & ~SLUB_DMA, "kmalloc_dma-%d",
+			 (unsigned int)realsize);
 	s = kmalloc(kmem_size, flags & ~SLUB_DMA);
 
 	if (!s || !text || !kmem_cache_open(s, flags, text,
@@ -3040,7 +3041,8 @@ void __init kmem_cache_init(void)
 #endif
 
 
-	printk(KERN_INFO "SLUB: Genslabs=%d, HWalign=%d, Order=%d-%d, MinObjects=%d,"
+	printk(KERN_INFO
+		"SLUB: Genslabs=%d, HWalign=%d, Order=%d-%d, MinObjects=%d,"
 		" CPUs=%d, Nodes=%d\n",
 		caches, cache_line_size(),
 		slub_min_order, slub_max_order, slub_min_objects,
@@ -3207,7 +3209,7 @@ static int __cpuinit slab_cpuup_callback(struct notifier_block *nfb,
 }
 
 static struct notifier_block __cpuinitdata slab_notifier = {
-	&slab_cpuup_callback, NULL, 0
+	.notifier_call = slab_cpuup_callback
 };
 
 #endif
@@ -3365,8 +3367,9 @@ static void resiliency_test(void)
 	p = kzalloc(32, GFP_KERNEL);
 	p[32 + sizeof(void *)] = 0x34;
 	printk(KERN_ERR "\n2. kmalloc-32: Clobber next pointer/next slab"
-		 	" 0x34 -> -0x%p\n", p);
-	printk(KERN_ERR "If allocated object is overwritten then not detectable\n\n");
+			" 0x34 -> -0x%p\n", p);
+	printk(KERN_ERR
+		"If allocated object is overwritten then not detectable\n\n");
 
 	validate_slab_cache(kmalloc_caches + 5);
 	p = kzalloc(64, GFP_KERNEL);
@@ -3374,7 +3377,8 @@ static void resiliency_test(void)
 	*p = 0x56;
 	printk(KERN_ERR "\n3. kmalloc-64: corrupting random byte 0x56->0x%p\n",
 									p);
-	printk(KERN_ERR "If allocated object is overwritten then not detectable\n\n");
+	printk(KERN_ERR
+		"If allocated object is overwritten then not detectable\n\n");
 	validate_slab_cache(kmalloc_caches + 6);
 
 	printk(KERN_ERR "\nB. Corruption after free\n");
@@ -3387,7 +3391,8 @@ static void resiliency_test(void)
 	p = kzalloc(256, GFP_KERNEL);
 	kfree(p);
 	p[50] = 0x9a;
-	printk(KERN_ERR "\n2. kmalloc-256: Clobber 50th byte 0x9a->0x%p\n\n", p);
+	printk(KERN_ERR "\n2. kmalloc-256: Clobber 50th byte 0x9a->0x%p\n\n",
+			p);
 	validate_slab_cache(kmalloc_caches + 8);
 
 	p = kzalloc(512, GFP_KERNEL);

commit 58d5d0d8dd52cbca988af24b5692a20b00285543
Author: Ingo Molnar <mingo@elte.hu>
Date:   Wed Feb 6 22:39:45 2008 +0100

    x86: fix deadlock, make pgd_lock irq-safe
    
    lockdep just caught this one:
    
    =================================
    [ INFO: inconsistent lock state ]
    2.6.24 #38
    ---------------------------------
    inconsistent {in-softirq-W} -> {softirq-on-W} usage.
    swapper/1 [HC0[0]:SC0[0]:HE1:SE1] takes:
     (pgd_lock){-+..}, at: [<ffffffff8022a9ea>] mm_init+0x1da/0x250
    {in-softirq-W} state was registered at:
      [<ffffffffffffffff>] 0xffffffffffffffff
    irq event stamp: 394559
    hardirqs last  enabled at (394559): [<ffffffff80267f0a>] get_page_from_freelist+0x30a/0x4c0
    hardirqs last disabled at (394558): [<ffffffff80267d25>] get_page_from_freelist+0x125/0x4c0
    softirqs last  enabled at (393952): [<ffffffff80232f8e>] __do_softirq+0xce/0xe0
    softirqs last disabled at (393945): [<ffffffff8020c57c>] call_softirq+0x1c/0x30
    
    other info that might help us debug this:
    no locks held by swapper/1.
    
    stack backtrace:
    Pid: 1, comm: swapper Not tainted 2.6.24 #38
    
    Call Trace:
     [<ffffffff8024e1fb>] print_usage_bug+0x18b/0x190
     [<ffffffff8024f55d>] mark_lock+0x53d/0x560
     [<ffffffff8024fffa>] __lock_acquire+0x3ca/0xed0
     [<ffffffff80250ba8>] lock_acquire+0xa8/0xe0
     [<ffffffff8022a9ea>] ? mm_init+0x1da/0x250
     [<ffffffff809bcd10>] _spin_lock+0x30/0x70
     [<ffffffff8022a9ea>] mm_init+0x1da/0x250
     [<ffffffff8022aa99>] mm_alloc+0x39/0x50
     [<ffffffff8028b95a>] bprm_mm_init+0x2a/0x1a0
     [<ffffffff8028d12b>] do_execve+0x7b/0x220
     [<ffffffff80209776>] sys_execve+0x46/0x70
     [<ffffffff8020c214>] kernel_execve+0x64/0xd0
     [<ffffffff8020901e>] ? _stext+0x1e/0x20
     [<ffffffff802090ba>] init_post+0x9a/0xf0
     [<ffffffff809bc5f6>] ? trace_hardirqs_on_thunk+0x35/0x3a
     [<ffffffff8024f75a>] ? trace_hardirqs_on+0xba/0xd0
     [<ffffffff8020c1a8>] ? child_rip+0xa/0x12
     [<ffffffff8020bcbc>] ? restore_args+0x0/0x44
     [<ffffffff8020c19e>] ? child_rip+0x0/0x12
    
    turns out that pgd_lock has been used on 64-bit x86 in an irq-unsafe
    way for almost two years, since commit 8c914cb704a11460e.
    
    Signed-off-by: Ingo Molnar <mingo@elte.hu>
    Signed-off-by: Thomas Gleixner <tglx@linutronix.de>

diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c
index d8ed4006b3d2..621afb6343dc 100644
--- a/arch/x86/mm/fault.c
+++ b/arch/x86/mm/fault.c
@@ -958,11 +958,12 @@ void vmalloc_sync_all(void)
 	for (address = start; address <= VMALLOC_END; address += PGDIR_SIZE) {
 		if (!test_bit(pgd_index(address), insync)) {
 			const pgd_t *pgd_ref = pgd_offset_k(address);
+			unsigned long flags;
 			struct page *page;
 
 			if (pgd_none(*pgd_ref))
 				continue;
-			spin_lock(&pgd_lock);
+			spin_lock_irqsave(&pgd_lock, flags);
 			list_for_each_entry(page, &pgd_list, lru) {
 				pgd_t *pgd;
 				pgd = (pgd_t *)page_address(page) + pgd_index(address);
@@ -971,7 +972,7 @@ void vmalloc_sync_all(void)
 				else
 					BUG_ON(pgd_page_vaddr(*pgd) != pgd_page_vaddr(*pgd_ref));
 			}
-			spin_unlock(&pgd_lock);
+			spin_unlock_irqrestore(&pgd_lock, flags);
 			set_bit(pgd_index(address), insync);
 		}
 		if (address == start)
diff --git a/include/asm-x86/pgalloc_64.h b/include/asm-x86/pgalloc_64.h
index 315314ce4bfb..4f6220db22b1 100644
--- a/include/asm-x86/pgalloc_64.h
+++ b/include/asm-x86/pgalloc_64.h
@@ -42,19 +42,21 @@ static inline void pud_free(struct mm_struct *mm, pud_t *pud)
 static inline void pgd_list_add(pgd_t *pgd)
 {
 	struct page *page = virt_to_page(pgd);
+	unsigned long flags;
 
-	spin_lock(&pgd_lock);
+	spin_lock_irqsave(&pgd_lock, flags);
 	list_add(&page->lru, &pgd_list);
-	spin_unlock(&pgd_lock);
+	spin_unlock_irqrestore(&pgd_lock, flags);
 }
 
 static inline void pgd_list_del(pgd_t *pgd)
 {
 	struct page *page = virt_to_page(pgd);
+	unsigned long flags;
 
-	spin_lock(&pgd_lock);
+	spin_lock_irqsave(&pgd_lock, flags);
 	list_del(&page->lru);
-	spin_unlock(&pgd_lock);
+	spin_unlock_irqrestore(&pgd_lock, flags);
 }
 
 static inline pgd_t *pgd_alloc(struct mm_struct *mm)

commit a09771bef9a375091f8ae706d992e20970e5d1e7
Author: Ingo Molnar <mingo@elte.hu>
Date:   Wed Feb 6 22:39:45 2008 +0100

    virtio: fix trivial build bug
    
    fix build bug:
    
      drivers/virtio/virtio_balloon.c: In function 'fill_balloon':
      drivers/virtio/virtio_balloon.c:98: error: implicit declaration of function 'msleep'
    
    Acked-by: Rusty Russell <rusty@rustcorp.com.au>
    Signed-off-by: Ingo Molnar <mingo@elte.hu>

diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c
index 622aece1acce..c8a4332d1132 100644
--- a/drivers/virtio/virtio_balloon.c
+++ b/drivers/virtio/virtio_balloon.c
@@ -23,6 +23,7 @@
 #include <linux/swap.h>
 #include <linux/kthread.h>
 #include <linux/freezer.h>
+#include <linux/delay.h>
 
 struct virtio_balloon
 {

commit 971a52d66a3e87d4d2f5d3455e62680447cdb8e9
Author: Ingo Molnar <mingo@elte.hu>
Date:   Wed Feb 6 22:39:45 2008 +0100

    x86: delay CPA self-test and repeat it
    
    delay the CPA self-test so that any impact (corruption) of
    user-space pagetables can be triggered. Repeat the test
    every 30 seconds.
    
    this would have prevented the bug fixed by 8cb2a7c1e95e472b5,
    at its source.
    
    Signed-off-by: Ingo Molnar <mingo@elte.hu>

diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug
index 2e1e3af28c3a..fa555148823d 100644
--- a/arch/x86/Kconfig.debug
+++ b/arch/x86/Kconfig.debug
@@ -220,9 +220,9 @@ config DEBUG_BOOT_PARAMS
 	  This option will cause struct boot_params to be exported via debugfs.
 
 config CPA_DEBUG
-	bool "CPA self test code"
+	bool "CPA self-test code"
 	depends on DEBUG_KERNEL
 	help
-	  Do change_page_attr self tests at boot.
+	  Do change_page_attr() self-tests every 30 seconds.
 
 endmenu
diff --git a/arch/x86/mm/pageattr-test.c b/arch/x86/mm/pageattr-test.c
index 398f3a578dde..ed8201600354 100644
--- a/arch/x86/mm/pageattr-test.c
+++ b/arch/x86/mm/pageattr-test.c
@@ -5,6 +5,7 @@
  * and compares page tables forwards and afterwards.
  */
 #include <linux/bootmem.h>
+#include <linux/kthread.h>
 #include <linux/random.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
@@ -14,8 +15,13 @@
 #include <asm/pgtable.h>
 #include <asm/kdebug.h>
 
+/*
+ * Only print the results of the first pass:
+ */
+static __read_mostly int print = 1;
+
 enum {
-	NTEST			= 4000,
+	NTEST			= 400,
 #ifdef CONFIG_X86_64
 	LPS			= (1 << PMD_SHIFT),
 #elif defined(CONFIG_X86_PAE)
@@ -31,7 +37,7 @@ struct split_state {
 	long min_exec, max_exec;
 };
 
-static __init int print_split(struct split_state *s)
+static int print_split(struct split_state *s)
 {
 	long i, expected, missed = 0;
 	int printed = 0;
@@ -82,10 +88,13 @@ static __init int print_split(struct split_state *s)
 				s->max_exec = addr;
 		}
 	}
-	printk(KERN_INFO
-		"CPA mapping 4k %lu large %lu gb %lu x %lu[%lx-%lx] miss %lu\n",
-		s->spg, s->lpg, s->gpg, s->exec,
-		s->min_exec != ~0UL ? s->min_exec : 0, s->max_exec, missed);
+	if (print) {
+		printk(KERN_INFO
+			" 4k %lu large %lu gb %lu x %lu[%lx-%lx] miss %lu\n",
+			s->spg, s->lpg, s->gpg, s->exec,
+			s->min_exec != ~0UL ? s->min_exec : 0,
+			s->max_exec, missed);
+	}
 
 	expected = (s->gpg*GPS + s->lpg*LPS)/PAGE_SIZE + s->spg + missed;
 	if (expected != i) {
@@ -96,11 +105,11 @@ static __init int print_split(struct split_state *s)
 	return err;
 }
 
-static unsigned long __initdata addr[NTEST];
-static unsigned int __initdata len[NTEST];
+static unsigned long addr[NTEST];
+static unsigned int len[NTEST];
 
 /* Change the global bit on random pages in the direct mapping */
-static __init int exercise_pageattr(void)
+static int pageattr_test(void)
 {
 	struct split_state sa, sb, sc;
 	unsigned long *bm;
@@ -110,7 +119,8 @@ static __init int exercise_pageattr(void)
 	int i, k;
 	int err;
 
-	printk(KERN_INFO "CPA exercising pageattr\n");
+	if (print)
+		printk(KERN_INFO "CPA self-test:\n");
 
 	bm = vmalloc((max_pfn_mapped + 7) / 8);
 	if (!bm) {
@@ -186,7 +196,6 @@ static __init int exercise_pageattr(void)
 
 	failed += print_split(&sb);
 
-	printk(KERN_INFO "CPA reverting everything\n");
 	for (i = 0; i < NTEST; i++) {
 		if (!addr[i])
 			continue;
@@ -214,12 +223,40 @@ static __init int exercise_pageattr(void)
 	failed += print_split(&sc);
 
 	if (failed) {
-		printk(KERN_ERR "CPA selftests NOT PASSED. Please report.\n");
+		printk(KERN_ERR "NOT PASSED. Please report.\n");
 		WARN_ON(1);
+		return -EINVAL;
 	} else {
-		printk(KERN_INFO "CPA selftests PASSED\n");
+		if (print)
+			printk(KERN_INFO "ok.\n");
 	}
 
 	return 0;
 }
-module_init(exercise_pageattr);
+
+static int do_pageattr_test(void *__unused)
+{
+	while (!kthread_should_stop()) {
+		schedule_timeout_interruptible(HZ*30);
+		if (pageattr_test() < 0)
+			break;
+		if (print)
+			print--;
+	}
+	return 0;
+}
+
+static int start_pageattr_test(void)
+{
+	struct task_struct *p;
+
+	p = kthread_create(do_pageattr_test, NULL, "pageattr-test");
+	if (!IS_ERR(p))
+		wake_up_process(p);
+	else
+		WARN_ON(1);
+
+	return 0;
+}
+
+module_init(start_pageattr_test);

commit 9f9975a55dbcd82ff4a222691a6dcd7b3145b9c0
Author: Ingo Molnar <mingo@elte.hu>
Date:   Wed Feb 6 22:39:45 2008 +0100

    generic: add __FINITDATA
    
    Signed-off-by: Ingo Molnar <mingo@elte.hu>

diff --git a/include/linux/init.h b/include/linux/init.h
index 90cdbbbbe077..a404a0055dd7 100644
--- a/include/linux/init.h
+++ b/include/linux/init.h
@@ -110,6 +110,7 @@
 #define __FINIT		.previous
 
 #define __INITDATA	.section	".init.data","aw"
+#define __FINITDATA	.previous
 
 #define __DEVINIT        .section	".devinit.text", "ax"
 #define __DEVINITDATA    .section	".devinit.data", "aw"

commit 32a932332c8bad842804842eaf9651ad6268e637
Author: Ingo Molnar <mingo@elte.hu>
Date:   Wed Feb 6 22:39:44 2008 +0100

    brk randomization: introduce CONFIG_COMPAT_BRK
    
    based on similar patch from: Pavel Machek <pavel@ucw.cz>
    
    Introduce CONFIG_COMPAT_BRK. If disabled then the kernel is free
    (but not obliged to) randomize the brk area.
    
    Heap randomization breaks ancient binaries, so we keep COMPAT_BRK
    enabled by default.
    
    Signed-off-by: Ingo Molnar <mingo@elte.hu>

diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 4628c42ca892..111771d38e6e 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -1077,7 +1077,7 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
 	current->mm->start_stack = bprm->p;
 
 #ifdef arch_randomize_brk
-	if (current->flags & PF_RANDOMIZE)
+	if ((current->flags & PF_RANDOMIZE) && (randomize_va_space > 1))
 		current->mm->brk = current->mm->start_brk =
 			arch_randomize_brk(current->mm);
 #endif
diff --git a/init/Kconfig b/init/Kconfig
index 87f50df58893..92b23e256614 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -541,6 +541,18 @@ config ELF_CORE
 	help
 	  Enable support for generating core dumps. Disabling saves about 4k.
 
+config COMPAT_BRK
+	bool "Disable heap randomization"
+	default y
+	help
+	  Randomizing heap placement makes heap exploits harder, but it
+	  also breaks ancient binaries (including anything libc5 based).
+	  This option changes the bootup default to heap randomization
+	  disabled, and can be overriden runtime by setting
+	  /proc/sys/kernel/randomize_va_space to 2.
+
+	  On non-ancient distros (post-2000 ones) Y is usually a safe choice.
+
 config BASE_FULL
 	default y
 	bool "Enable full-sized data structures for core" if EMBEDDED
diff --git a/mm/memory.c b/mm/memory.c
index 7bb70728bb52..9d073fa0a2d0 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -82,7 +82,18 @@ void * high_memory;
 EXPORT_SYMBOL(num_physpages);
 EXPORT_SYMBOL(high_memory);
 
-int randomize_va_space __read_mostly = 1;
+/*
+ * Randomize the address space (stacks, mmaps, brk, etc.).
+ *
+ * ( When CONFIG_COMPAT_BRK=y we exclude brk from randomization,
+ *   as ancient (libc5 based) binaries can segfault. )
+ */
+int randomize_va_space __read_mostly =
+#ifdef CONFIG_COMPAT_BRK
+					1;
+#else
+					2;
+#endif
 
 static int __init disable_randmaps(char *s)
 {

commit 2d684cd6d9cf0c6a0e28978362671b6e2d8fb56c
Author: Ingo Molnar <mingo@elte.hu>
Date:   Wed Feb 6 22:39:44 2008 +0100

    x86: remove X2 workaround
    
    With the spurious handler fix, the X2 does not lock up anymore.
    
    Signed-off-by: Ingo Molnar <mingo@elte.hu>

diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c
index 16ce841f08d6..c870424aa9ad 100644
--- a/arch/x86/mm/pageattr.c
+++ b/arch/x86/mm/pageattr.c
@@ -260,17 +260,6 @@ try_preserve_large_page(pte_t *kpte, unsigned long address,
 	pgprot_t old_prot, new_prot;
 	int level, do_split = 1;
 
-	/*
-	 * An Athlon 64 X2 showed hard hangs if we tried to preserve
-	 * largepages and changed the PSE entry from RW to RO.
-	 *
-	 * As AMD CPUs have a long series of erratas in this area,
-	 * (and none of the known ones seem to explain this hang),
-	 * disable this code until the hang can be debugged:
-	 */
-	if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
-		return 1;
-
 	spin_lock_irqsave(&pgd_lock, flags);
 	/*
 	 * Check for races, another CPU might have split this page

commit 87f7f8fe328388a1430a4c27cbe684f3925fd8a5
Author: Ingo Molnar <mingo@elte.hu>
Date:   Mon Feb 4 16:48:10 2008 +0100

    x86: cpa, clean up code flow
    
    Signed-off-by: Ingo Molnar <mingo@elte.hu>
    Signed-off-by: Thomas Gleixner <tglx@linutronix.de>

diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c
index fb2eedba76ad..4f033505127e 100644
--- a/arch/x86/mm/pageattr.c
+++ b/arch/x86/mm/pageattr.c
@@ -423,8 +423,8 @@ static int split_large_page(pte_t *kpte, unsigned long address)
 
 static int __change_page_attr(unsigned long address, struct cpa_data *cpa)
 {
+	int level, do_split, err;
 	struct page *kpte_page;
-	int level, do_split;
 	pte_t *kpte;
 
 repeat:
@@ -476,26 +476,24 @@ static int __change_page_attr(unsigned long address, struct cpa_data *cpa)
 	 * and just change the pte:
 	 */
 	do_split = try_preserve_large_page(kpte, address, cpa);
-	if (do_split < 0)
-		return do_split;
-
 	/*
 	 * When the range fits into the existing large page,
 	 * return. cp->numpages and cpa->tlbflush have been updated in
 	 * try_large_page:
 	 */
-	if (do_split == 0)
-		return 0;
+	if (do_split <= 0)
+		return do_split;
 
 	/*
 	 * We have to split the large page:
 	 */
-	do_split = split_large_page(kpte, address);
-	if (do_split)
-		return do_split;
-	cpa->flushtlb = 1;
+	err = split_large_page(kpte, address);
+	if (!err) {
+		cpa->flushtlb = 1;
+		goto repeat;
+	}
 
-	goto repeat;
+	return err;
 }
 
 /**

commit beaff6333b4a21e8f3b7f9a7c3c8f8716b2334bc
Author: Ingo Molnar <mingo@elte.hu>
Date:   Mon Feb 4 16:48:09 2008 +0100

    x86: cpa, eliminate CPA_ enum
    
    Signed-off-by: Ingo Molnar <mingo@elte.hu>
    Signed-off-by: Thomas Gleixner <tglx@linutronix.de>

diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c
index 029fb07b3f03..fb2eedba76ad 100644
--- a/arch/x86/mm/pageattr.c
+++ b/arch/x86/mm/pageattr.c
@@ -27,11 +27,6 @@ struct cpa_data {
 	int		flushtlb;
 };
 
-enum {
-	CPA_NO_SPLIT = 0,
-	CPA_SPLIT,
-};
-
 static inline int
 within(unsigned long addr, unsigned long start, unsigned long end)
 {
@@ -263,7 +258,7 @@ try_preserve_large_page(pte_t *kpte, unsigned long address,
 	unsigned long nextpage_addr, numpages, pmask, psize, flags;
 	pte_t new_pte, old_pte, *tmp;
 	pgprot_t old_prot, new_prot;
-	int level, res = CPA_SPLIT;
+	int level, do_split = 1;
 
 	/*
 	 * An Athlon 64 X2 showed hard hangs if we tried to preserve
@@ -274,7 +269,7 @@ try_preserve_large_page(pte_t *kpte, unsigned long address,
 	 * disable this code until the hang can be debugged:
 	 */
 	if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
-		return res;
+		return 1;
 
 	spin_lock_irqsave(&pgd_lock, flags);
 	/*
@@ -297,7 +292,7 @@ try_preserve_large_page(pte_t *kpte, unsigned long address,
 		break;
 #endif
 	default:
-		res = -EINVAL;
+		do_split = -EINVAL;
 		goto out_unlock;
 	}
 
@@ -325,7 +320,7 @@ try_preserve_large_page(pte_t *kpte, unsigned long address,
 	 * above:
 	 */
 	if (pgprot_val(new_prot) == pgprot_val(old_prot)) {
-		res = CPA_NO_SPLIT;
+		do_split = 0;
 		goto out_unlock;
 	}
 
@@ -345,13 +340,13 @@ try_preserve_large_page(pte_t *kpte, unsigned long address,
 		new_pte = pfn_pte(pte_pfn(old_pte), canon_pgprot(new_prot));
 		__set_pmd_pte(kpte, address, new_pte);
 		cpa->flushtlb = 1;
-		res = CPA_NO_SPLIT;
+		do_split = 0;
 	}
 
 out_unlock:
 	spin_unlock_irqrestore(&pgd_lock, flags);
 
-	return res;
+	return do_split;
 }
 
 static int split_large_page(pte_t *kpte, unsigned long address)
@@ -429,7 +424,7 @@ static int split_large_page(pte_t *kpte, unsigned long address)
 static int __change_page_attr(unsigned long address, struct cpa_data *cpa)
 {
 	struct page *kpte_page;
-	int level, res;
+	int level, do_split;
 	pte_t *kpte;
 
 repeat:
@@ -480,25 +475,26 @@ static int __change_page_attr(unsigned long address, struct cpa_data *cpa)
 	 * Check, whether we can keep the large page intact
 	 * and just change the pte:
 	 */
-	res = try_preserve_large_page(kpte, address, cpa);
-	if (res < 0)
-		return res;
+	do_split = try_preserve_large_page(kpte, address, cpa);
+	if (do_split < 0)
+		return do_split;
 
 	/*
 	 * When the range fits into the existing large page,
 	 * return. cp->numpages and cpa->tlbflush have been updated in
 	 * try_large_page:
 	 */
-	if (res == CPA_NO_SPLIT)
+	if (do_split == 0)
 		return 0;
 
 	/*
 	 * We have to split the large page:
 	 */
-	res = split_large_page(kpte, address);
-	if (res)
-		return res;
+	do_split = split_large_page(kpte, address);
+	if (do_split)
+		return do_split;
 	cpa->flushtlb = 1;
+
 	goto repeat;
 }