[PATCH] x86_64: Fix reference counting bug in change_page_attr on i386/x86-64

Linux Kernel Mailing List <[email protected]> Thu, 07 Apr 2005 12:07:52 +0000
Newsgroups gmane.linux.kernel.commits.2-4
Message-ID <[email protected]>
ChangeSet 1.1499, 2005/04/07 09:07:52-03:00, [email protected]

	[PATCH] x86_64: Fix reference counting bug in change_page_attr on i386/x86-64
	
	Fix reference counting bug in change_page_attr on i386/x86-64
	
	When not splitting a page the reference count must be increased too.
	Found by several people in 2.6, one of them was Andrea Arcangelli, other
	names I don't remember (sorry).
	
	Signed-off-by: Andi Kleen <[email protected]>
	
	Index: linux/arch/i386/mm/pageattr.c
	===================================================================



 i386/mm/pageattr.c   |    8 ++------
 x86_64/mm/pageattr.c |    9 +++------
 2 files changed, 5 insertions(+), 12 deletions(-)


diff -Nru a/arch/i386/mm/pageattr.c b/arch/i386/mm/pageattr.c
--- a/arch/i386/mm/pageattr.c	2005-04-07 11:04:03 -07:00
+++ b/arch/i386/mm/pageattr.c	2005-04-07 11:04:03 -07:00
@@ -119,19 +119,15 @@
 	kpte_page = virt_to_page(((unsigned long)kpte) & PAGE_MASK);
 	if (pgprot_val(prot) != pgprot_val(PAGE_KERNEL)) { 
 		if ((pte_val(*kpte) & _PAGE_PSE) == 0) {
-			pte_t old = *kpte;
-			pte_t standard = mk_pte(page, PAGE_KERNEL); 
-
 			set_pte_atomic(kpte, mk_pte(page, prot)); 
-			if (pte_same(old,standard))
-				atomic_inc(&kpte_page->count);
 		} else {
 			struct page *split = split_large_page(address, prot); 
 			if (!split)
 				return -ENOMEM;
-			atomic_inc(&kpte_page->count); 	
 			set_pmd_pte(kpte,address,mk_pte(split, PAGE_KERNEL));
+			kpte_page = split;
 		}	
+		atomic_inc(&kpte_page->count);
 	} else if ((pte_val(*kpte) & _PAGE_PSE) == 0) { 
 		set_pte_atomic(kpte, mk_pte(page, PAGE_KERNEL));
 		atomic_dec(&kpte_page->count); 
diff -Nru a/arch/x86_64/mm/pageattr.c b/arch/x86_64/mm/pageattr.c
--- a/arch/x86_64/mm/pageattr.c	2005-04-07 11:04:03 -07:00
+++ b/arch/x86_64/mm/pageattr.c	2005-04-07 11:04:03 -07:00
@@ -101,18 +101,15 @@
 	kpte_page = virt_to_page(((unsigned long)kpte) & PAGE_MASK);
 	if (pgprot_val(prot) != pgprot_val(PAGE_KERNEL)) { 
 		if ((pte_val(*kpte) & _PAGE_PSE) == 0) { 
-			pte_t old = *kpte;
-			pte_t standard = mk_pte(page, PAGE_KERNEL); 
-
 			set_pte(kpte, mk_pte(page, prot)); 
-			if (pte_same(old,standard))
-				atomic_inc(&kpte_page->count);
 		} else {
 			struct page *split = split_large_page(address, prot); 
 			if (!split)
 				return -ENOMEM;
 			set_pte(kpte,mk_pte(split, PAGE_KERNEL));
-		}	
+			kpte_page = split;
+		}
+		atomic_inc(&kpte_page->count);	
 	} else if ((pte_val(*kpte) & _PAGE_PSE) == 0) { 
 		set_pte(kpte, mk_pte(page, PAGE_KERNEL));
 		atomic_dec(&kpte_page->count);