x86/mm: fix slow_virt_to_phys() for X86_PAE again
Subsystems (3)
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.
--- arch/x86/mm/pageattr.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-)
arch/x86/mm/pageattr.c +10 -4
@@ -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>
Quoted 14 lines · Dexuan Cui
"
d1cd12108346: x86, pageattr: Prevent overflow inslow_virt_to_phys()forX86_PAE"
was unintentionally removed by the recent
"34437e67a672: x86/mm: Fixslow_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: Fixslow_virt_to_phys()to handle large PAT bit"
Quoted 12 lines
Signed-off-by Dexuan Cui <[email protected]>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]>
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>
tip-bot for Dexuan Cui
merge bot[tip:x86/urgent] x86/mm: Fix slow_virt_to_phys() for X86_PAE again
In reply to Dexuan Cuix86/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.
--- arch/x86/mm/pageattr.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-)
arch/x86/mm/pageattr.c +10 -4
@@ -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 ; }