Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 89877e42827f16fa5f86b1df0c2860b1 > files > 2528

kernel-2.6.18-128.1.10.el5.src.rpm

From: Larry Woodman <lwoodman@redhat.com>
Subject: Re: [RHEL5 patch] x86_64: clear_kernel_mapping: mapping has been  split. will leak memory.
Date: Wed, 13 Dec 2006 15:01:27 -0500
Bugzilla: 218543
Message-Id: <45805C17.5090100@redhat.com>
Changelog: x86_64: clear_kernel_mapping: mapping has been split. will leak memory.


Konrad Rzeszutek wrote:

>I will NACK it based on testing. Please see attached dmesg.
>
>
>Bad page state in process 'swapper'
>page:ffff810001c3ff28 flags:0x0030080000000800 mapping:0000000000000000 
>mapcount:0 count:0 (Not tainted)
>Trying to fix it up, but a reboot is needed
>Backtrace:
>
> 
>
OK, the problem here is that split_large_page() sets the PG_private flag and
sets page->private = 0 for accounting purposes.

--------------------------------------------------------------------
split_large_page(...)
      ...
       /*
        * page_private is used to track the number of entries in
        * the page table page have non standard attributes.
        */
       SetPagePrivate(base);
       page_private(base) = 0;
      ...
--------------------------------------------------------------------

clear_kernel_mapping() simply needs to call ClearPagePrivate() before
freeing the page table page.




--- linux-2.6.18.noarch/arch/x86_64/mm/init.c.orig
+++ linux-2.6.18.noarch/arch/x86_64/mm/init.c
@@ -413,7 +413,9 @@ void __init clear_kernel_mapping(unsigne
 	for (; address < end; address += LARGE_PAGE_SIZE) { 
 		pgd_t *pgd = pgd_offset_k(address);
 		pud_t *pud;
-		pmd_t *pmd;
+		pmd_t *pmd, local_pmd;
+		struct page *page;
+
 		if (pgd_none(*pgd))
 			continue;
 		pud = pud_offset(pgd, address);
@@ -423,10 +425,10 @@ void __init clear_kernel_mapping(unsigne
 		if (!pmd || pmd_none(*pmd))
 			continue; 
 		if (0 == (pmd_val(*pmd) & _PAGE_PSE)) { 
-			/* Could handle this, but it should not happen currently. */
-			printk(KERN_ERR 
-	       "clear_kernel_mapping: mapping has been split. will leak memory\n"); 
-			pmd_ERROR(*pmd); 
+			local_pmd = __pmd(pmd_val(*pmd) & ~_PAGE_NX);
+			page = pmd_page(local_pmd);
+			ClearPagePrivate(page);
+			pte_free(pmd_page(local_pmd));
 		}
 		set_pmd(pmd, __pmd(0)); 		
 	}
--- linux-2.6.18.noarch/arch/x86_64/mm/init-xen.c.orig
+++ linux-2.6.18.noarch/arch/x86_64/mm/init-xen.c
@@ -811,7 +811,9 @@ void __init clear_kernel_mapping(unsigne
 	for (; address < end; address += LARGE_PAGE_SIZE) { 
 		pgd_t *pgd = pgd_offset_k(address);
 		pud_t *pud;
-		pmd_t *pmd;
+		pmd_t *pmd, local_pmd;
+		struct page *page;
+
 		if (pgd_none(*pgd))
 			continue;
 		pud = pud_offset(pgd, address);
@@ -821,10 +823,10 @@ void __init clear_kernel_mapping(unsigne
 		if (!pmd || pmd_none(*pmd))
 			continue; 
 		if (0 == (pmd_val(*pmd) & _PAGE_PSE)) { 
-			/* Could handle this, but it should not happen currently. */
-			printk(KERN_ERR 
-	       "clear_kernel_mapping: mapping has been split. will leak memory\n"); 
-			pmd_ERROR(*pmd); 
+			local_pmd = __pmd(pmd_val(*pmd) & ~_PAGE_NX);
+			page = pmd_page(local_pmd);
+			ClearPagePrivate(page);
+			pte_free(pmd_page(local_pmd));
 		}
 		set_pmd(pmd, __pmd(0)); 		
 	}