diff options
author | Dexuan Cui <decui@microsoft.com> | 2016-02-25 04:58:12 -0500 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2016-02-25 13:53:15 -0500 |
commit | bf70e5513dfea29c3682e7eb3dbb45f0723bac09 (patch) | |
tree | 1a51a4cc28ecb10799e8c9e96504ce78081065d8 | |
parent | 3d44d51bd339766f0178f0cf2e8d048b4a4872aa (diff) |
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"
Signed-off-by: Dexuan Cui <decui@microsoft.com>
Reviewed-by: Toshi Kani <toshi.kani@hpe.com>
Cc: olaf@aepfle.de
Cc: gregkh@linuxfoundation.org
Cc: jasowang@redhat.com
Cc: driverdev-devel@linuxdriverproject.org
Cc: linux-mm@kvack.org
Cc: apw@canonical.com
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: K. Y. Srinivasan <kys@microsoft.com>
Cc: Haiyang Zhang <haiyangz@microsoft.com>
Link: http://lkml.kernel.org/r/1456394292-9030-1-git-send-email-decui@microsoft.com
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r-- | arch/x86/mm/pageattr.c | 14 |
1 files changed, 10 insertions, 4 deletions
diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c index 2440814b0069..9cf96d82147a 100644 --- a/arch/x86/mm/pageattr.c +++ b/arch/x86/mm/pageattr.c | |||
@@ -419,24 +419,30 @@ pmd_t *lookup_pmd_address(unsigned long address) | |||
419 | phys_addr_t slow_virt_to_phys(void *__virt_addr) | 419 | phys_addr_t slow_virt_to_phys(void *__virt_addr) |
420 | { | 420 | { |
421 | unsigned long virt_addr = (unsigned long)__virt_addr; | 421 | unsigned long virt_addr = (unsigned long)__virt_addr; |
422 | unsigned long phys_addr, offset; | 422 | phys_addr_t phys_addr; |
423 | unsigned long offset; | ||
423 | enum pg_level level; | 424 | enum pg_level level; |
424 | pte_t *pte; | 425 | pte_t *pte; |
425 | 426 | ||
426 | pte = lookup_address(virt_addr, &level); | 427 | pte = lookup_address(virt_addr, &level); |
427 | BUG_ON(!pte); | 428 | BUG_ON(!pte); |
428 | 429 | ||
430 | /* | ||
431 | * pXX_pfn() returns unsigned long, which must be cast to phys_addr_t | ||
432 | * before being left-shifted PAGE_SHIFT bits -- this trick is to | ||
433 | * make 32-PAE kernel work correctly. | ||
434 | */ | ||
429 | switch (level) { | 435 | switch (level) { |
430 | case PG_LEVEL_1G: | 436 | case PG_LEVEL_1G: |
431 | phys_addr = pud_pfn(*(pud_t *)pte) << PAGE_SHIFT; | 437 | phys_addr = (phys_addr_t)pud_pfn(*(pud_t *)pte) << PAGE_SHIFT; |
432 | offset = virt_addr & ~PUD_PAGE_MASK; | 438 | offset = virt_addr & ~PUD_PAGE_MASK; |
433 | break; | 439 | break; |
434 | case PG_LEVEL_2M: | 440 | case PG_LEVEL_2M: |
435 | phys_addr = pmd_pfn(*(pmd_t *)pte) << PAGE_SHIFT; | 441 | phys_addr = (phys_addr_t)pmd_pfn(*(pmd_t *)pte) << PAGE_SHIFT; |
436 | offset = virt_addr & ~PMD_PAGE_MASK; | 442 | offset = virt_addr & ~PMD_PAGE_MASK; |
437 | break; | 443 | break; |
438 | default: | 444 | default: |
439 | phys_addr = pte_pfn(*pte) << PAGE_SHIFT; | 445 | phys_addr = (phys_addr_t)pte_pfn(*pte) << PAGE_SHIFT; |
440 | offset = virt_addr & ~PAGE_MASK; | 446 | offset = virt_addr & ~PAGE_MASK; |
441 | } | 447 | } |
442 | 448 | ||