Skip to contentSkip to conversation

x86/mm: fix slow_virt_to_phys() for X86_PAE again

PATCH In review Dexuan Cui 3 participants 3 messages Feb 25, 2016

Subsystems (3)
lore
Share & tools
lore

Dexuan Cui

author
#0 lore raw

PATCH 1/1 x86/mm: fix slow_virt_to_phys() for X86_PAE again

"d1cd12108346: x86, pageattr: Prevent overflow in slow_virt_to_phys() for X86_PAE" was unintentionally removed by the recent
"34437e67a672: x86/mm: Fix slow_virt_to_phys() to handle large PAT bit".

And, the variable 'phys_addr' was defined as "unsigned long" by mistake -- it should be "phys_addr_t".

As a result, Hyper-V network driver in 32-PAE Linux guest can't work again.

Fixes "commmit 34437e67a672: x86/mm: Fix slow_virt_to_phys() to handle large PAT bit"
Cc Toshi Kani <[email protected]>
Cc Andrew Morton <[email protected]>
Cc Thomas Gleixner <[email protected]>
Cc K. Y. Srinivasan <[email protected]>
Cc Haiyang Zhang <[email protected]>
---
 arch/x86/mm/pageattr.c | 14 ++++++++++----
 1 file changed, 10 insertions(+), 4 deletions(-)
arch/x86/mm/pageattr.c +10 -4
index 2440814..9cf96d8 100644
@@ -419,24 +419,30 @@ pmd_t *lookup_pmd_address(unsigned long address)
 phys_addr_t slow_virt_to_phys(void *__virt_addr)
 {
 	unsigned long virt_addr = (unsigned long)__virt_addr;
-	unsigned long phys_addr, offset;
+	phys_addr_t phys_addr;
+	unsigned long offset;
 	enum pg_level level;
 	pte_t *pte;
 
 	pte = lookup_address(virt_addr, &level);
 	BUG_ON(!pte);
 
+	/*
+	 * pXX_pfn() returns unsigned long, which must be cast to phys_addr_t
+	 * before being left-shifted PAGE_SHIFT bits -- this trick is to
+	 * make 32-PAE kernel work correctly.
+	 */
 	switch (level) {
 	case PG_LEVEL_1G:
-		phys_addr = pud_pfn(*(pud_t *)pte) << PAGE_SHIFT;
+		phys_addr = (phys_addr_t)pud_pfn(*(pud_t *)pte) << PAGE_SHIFT;
 		offset = virt_addr & ~PUD_PAGE_MASK;
 		break;
 	case PG_LEVEL_2M:
-		phys_addr = pmd_pfn(*(pmd_t *)pte) << PAGE_SHIFT;
+		phys_addr = (phys_addr_t)pmd_pfn(*(pmd_t *)pte) << PAGE_SHIFT;
 		offset = virt_addr & ~PMD_PAGE_MASK;
 		break;
 	default:
-		phys_addr = pte_pfn(*pte) << PAGE_SHIFT;
+		phys_addr = (phys_addr_t)pte_pfn(*pte) << PAGE_SHIFT;
 		offset = virt_addr & ~PAGE_MASK;
 	}
 
Signature · 7 lines
1.9.1

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected].  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Reviewed-by on v1 1/1
#1 lore raw
Quoted 14 lines · Dexuan Cui

"d1cd12108346: x86, pageattr: Prevent overflow in slow_virt_to_phys() for X86_PAE"
was unintentionally removed by the recent
"34437e67a672: x86/mm: Fix slow_virt_to_phys() to handle large PAT bit".

And, the variable 'phys_addr' was defined as "unsigned long" by mistake -- it should
be "phys_addr_t".

As a result, Hyper-V network driver in 32-PAE Linux guest can't work again.

Fixes: "commmit 34437e67a672: x86/mm: Fix slow_virt_to_phys() to handle large PAT bit"

Quoted 12 lines

Thanks for the fix and adding the comment to explain the trick! A The change looks good to me.

-Toshi

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#2 lore raw

[tip:x86/urgent] x86/mm: Fix slow_virt_to_phys() for X86_PAE again

In reply to Dexuan Cui
x86/mm: Fix slow_virt_to_phys() for X86_PAE again
Commit-ID:  bf70e5513dfea29c3682e7eb3dbb45f0723bac09
Gitweb:     http://git.kernel.org/tip/bf70e5513dfea29c3682e7eb3dbb45f0723bac09
Author:     Dexuan Cui <[email protected]>
AuthorDate: Thu, 25 Feb 2016 01:58:12 -0800
Committer:  Thomas Gleixner <[email protected]>
CommitDate: Thu, 25 Feb 2016 19:53:15 +0100

x86/mm: Fix slow_virt_to_phys() for X86_PAE again

"d1cd12108346: x86, pageattr: Prevent overflow in slow_virt_to_phys() for X86_PAE" was unintentionally removed by the recent "34437e67a672: x86/mm: Fix slow_virt_to_phys() to handle large PAT bit".

And, the variable 'phys_addr' was defined as "unsigned long" by mistake -- it should be "phys_addr_t".

As a result, Hyper-V network driver in 32-PAE Linux guest can't work again.

Fixes commit 34437e67a672: "x86/mm: Fix slow_virt_to_phys() to handle large PAT bit"
Cc Andrew Morton <[email protected]>
Cc K. Y. Srinivasan <[email protected]>
Cc Haiyang Zhang <[email protected]>
---
 arch/x86/mm/pageattr.c | 14 ++++++++++----
 1 file changed, 10 insertions(+), 4 deletions(-)
arch/x86/mm/pageattr.c +10 -4
index 2440814..9cf96d8 100644
@@ -419,24 +419,30 @@ pmd_t *lookup_pmd_address(unsigned long address)
 phys_addr_t slow_virt_to_phys(void *__virt_addr)
 {
 	unsigned long virt_addr = (unsigned long)__virt_addr;
-	unsigned long phys_addr, offset;
+	phys_addr_t phys_addr;
+	unsigned long offset;
 	enum pg_level level;
 	pte_t *pte;
 
 	pte = lookup_address(virt_addr, &level);
 	BUG_ON(!pte);
 
+	/*
+	 * pXX_pfn() returns unsigned long, which must be cast to phys_addr_t
+	 * before being left-shifted PAGE_SHIFT bits -- this trick is to
+	 * make 32-PAE kernel work correctly.
+	 */
 	switch (level) {
 	case PG_LEVEL_1G:
-		phys_addr = pud_pfn(*(pud_t *)pte) << PAGE_SHIFT;
+		phys_addr = (phys_addr_t)pud_pfn(*(pud_t *)pte) << PAGE_SHIFT;
 		offset = virt_addr & ~PUD_PAGE_MASK;
 		break;
 	case PG_LEVEL_2M:
-		phys_addr = pmd_pfn(*(pmd_t *)pte) << PAGE_SHIFT;
+		phys_addr = (phys_addr_t)pmd_pfn(*(pmd_t *)pte) << PAGE_SHIFT;
 		offset = virt_addr & ~PMD_PAGE_MASK;
 		break;
 	default:
-		phys_addr = pte_pfn(*pte) << PAGE_SHIFT;
+		phys_addr = (phys_addr_t)pte_pfn(*pte) << PAGE_SHIFT;
 		offset = virt_addr & ~PAGE_MASK;
 	}