powerpc/mce: Fix MCE handling for huge pages
diff mbox series

Message ID 20191016195043.31040-2-manoj.iyer@canonical.com
State New
Headers show
Series
  • powerpc/mce: Fix MCE handling for huge pages
Related show

Commit Message

Manoj Iyer Oct. 16, 2019, 7:50 p.m. UTC
From: Balbir Singh <bsingharora@gmail.com>

The current code would fail on huge pages addresses, since the shift would
be incorrect. Use the correct page shift value returned by
__find_linux_pte() to get the correct physical address. The code is more
generic and can handle both regular and compound pages.

BugLink: https://bugs.launchpad.net/bugs/1848127

Fixes: ba41e1e1ccb9 ("powerpc/mce: Hookup derror (load/store) UE errors")
Signed-off-by: Balbir Singh <bsingharora@gmail.com>
[arbab@linux.ibm.com: Fixup pseries_do_memory_failure()]
Signed-off-by: Reza Arbab <arbab@linux.ibm.com>
Tested-by: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
Signed-off-by: Santosh Sivaraj <santosh@fossix.org>
Cc: stable@vger.kernel.org # v4.15+
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/20190820081352.8641-3-santosh@fossix.org
(cherry picked from commit 99ead78afd1128bfcebe7f88f3b102fb2da09aee)
Signed-off-by: Manoj Iyer <manoj.iyer@canonical.com>
---
 arch/powerpc/kernel/mce_power.c | 19 +++++++++++++------
 1 file changed, 13 insertions(+), 6 deletions(-)

Comments

Kleber Souza Oct. 17, 2019, 11:13 a.m. UTC | #1
On 16.10.19 21:50, Manoj Iyer wrote:
> From: Balbir Singh <bsingharora@gmail.com>
> 
> The current code would fail on huge pages addresses, since the shift would
> be incorrect. Use the correct page shift value returned by
> __find_linux_pte() to get the correct physical address. The code is more
> generic and can handle both regular and compound pages.
> 
> BugLink: https://bugs.launchpad.net/bugs/1848127
> 
> Fixes: ba41e1e1ccb9 ("powerpc/mce: Hookup derror (load/store) UE errors")
> Signed-off-by: Balbir Singh <bsingharora@gmail.com>
> [arbab@linux.ibm.com: Fixup pseries_do_memory_failure()]
> Signed-off-by: Reza Arbab <arbab@linux.ibm.com>
> Tested-by: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
> Signed-off-by: Santosh Sivaraj <santosh@fossix.org>
> Cc: stable@vger.kernel.org # v4.15+
> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
> Link: https://lore.kernel.org/r/20190820081352.8641-3-santosh@fossix.org
> (cherry picked from commit 99ead78afd1128bfcebe7f88f3b102fb2da09aee)
> Signed-off-by: Manoj Iyer <manoj.iyer@canonical.com>

Acked-by: Kleber Sacilotto de Souza <kleber.souza@canonical.com>

> ---
>  arch/powerpc/kernel/mce_power.c | 19 +++++++++++++------
>  1 file changed, 13 insertions(+), 6 deletions(-)
> 
> diff --git a/arch/powerpc/kernel/mce_power.c b/arch/powerpc/kernel/mce_power.c
> index a814d2dfb5b0..714a98e0927f 100644
> --- a/arch/powerpc/kernel/mce_power.c
> +++ b/arch/powerpc/kernel/mce_power.c
> @@ -26,6 +26,7 @@
>  unsigned long addr_to_pfn(struct pt_regs *regs, unsigned long addr)
>  {
>  	pte_t *ptep;
> +	unsigned int shift;
>  	unsigned long flags;
>  	struct mm_struct *mm;
>  
> @@ -35,13 +36,18 @@ unsigned long addr_to_pfn(struct pt_regs *regs, unsigned long addr)
>  		mm = &init_mm;
>  
>  	local_irq_save(flags);
> -	if (mm == current->mm)
> -		ptep = find_current_mm_pte(mm->pgd, addr, NULL, NULL);
> -	else
> -		ptep = find_init_mm_pte(addr, NULL);
> +	ptep = __find_linux_pte(mm->pgd, addr, NULL, &shift);
>  	local_irq_restore(flags);
> +
>  	if (!ptep || pte_special(*ptep))
>  		return ULONG_MAX;
> +
> +	if (shift > PAGE_SHIFT) {
> +		unsigned long rpnmask = (1ul << shift) - PAGE_SIZE;
> +
> +		return pte_pfn(__pte(pte_val(*ptep) | (addr & rpnmask)));
> +	}
> +
>  	return pte_pfn(*ptep);
>  }
>  
> @@ -344,7 +350,7 @@ static const struct mce_derror_table mce_p9_derror_table[] = {
>    MCE_INITIATOR_CPU,   MCE_SEV_SEVERE, true },
>  { 0, false, 0, 0, 0, 0, 0 } };
>  
> -static int mce_find_instr_ea_and_pfn(struct pt_regs *regs, uint64_t *addr,
> +static int mce_find_instr_ea_and_phys(struct pt_regs *regs, uint64_t *addr,
>  					uint64_t *phys_addr)
>  {
>  	/*
> @@ -541,7 +547,8 @@ static int mce_handle_derror(struct pt_regs *regs,
>  			 * kernel/exception-64s.h
>  			 */
>  			if (get_paca()->in_mce < MAX_MCE_DEPTH)
> -				mce_find_instr_ea_and_pfn(regs, addr, phys_addr);
> +				mce_find_instr_ea_and_phys(regs, addr,
> +							   phys_addr);
>  		}
>  		found = 1;
>  	}
>
Stefan Bader Oct. 18, 2019, 1:29 p.m. UTC | #2
On 16.10.19 21:50, Manoj Iyer wrote:
> From: Balbir Singh <bsingharora@gmail.com>
> 
> The current code would fail on huge pages addresses, since the shift would
> be incorrect. Use the correct page shift value returned by
> __find_linux_pte() to get the correct physical address. The code is more
> generic and can handle both regular and compound pages.
> 
> BugLink: https://bugs.launchpad.net/bugs/1848127
> 
> Fixes: ba41e1e1ccb9 ("powerpc/mce: Hookup derror (load/store) UE errors")
> Signed-off-by: Balbir Singh <bsingharora@gmail.com>
> [arbab@linux.ibm.com: Fixup pseries_do_memory_failure()]
> Signed-off-by: Reza Arbab <arbab@linux.ibm.com>
> Tested-by: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
> Signed-off-by: Santosh Sivaraj <santosh@fossix.org>
> Cc: stable@vger.kernel.org # v4.15+
> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
> Link: https://lore.kernel.org/r/20190820081352.8641-3-santosh@fossix.org
> (cherry picked from commit 99ead78afd1128bfcebe7f88f3b102fb2da09aee)
> Signed-off-by: Manoj Iyer <manoj.iyer@canonical.com>
Acked-by: Stefan Bader <stefan.bader@canonical.com>
> ---
>  arch/powerpc/kernel/mce_power.c | 19 +++++++++++++------
>  1 file changed, 13 insertions(+), 6 deletions(-)
> 
> diff --git a/arch/powerpc/kernel/mce_power.c b/arch/powerpc/kernel/mce_power.c
> index a814d2dfb5b0..714a98e0927f 100644
> --- a/arch/powerpc/kernel/mce_power.c
> +++ b/arch/powerpc/kernel/mce_power.c
> @@ -26,6 +26,7 @@
>  unsigned long addr_to_pfn(struct pt_regs *regs, unsigned long addr)
>  {
>  	pte_t *ptep;
> +	unsigned int shift;
>  	unsigned long flags;
>  	struct mm_struct *mm;
>  
> @@ -35,13 +36,18 @@ unsigned long addr_to_pfn(struct pt_regs *regs, unsigned long addr)
>  		mm = &init_mm;
>  
>  	local_irq_save(flags);
> -	if (mm == current->mm)
> -		ptep = find_current_mm_pte(mm->pgd, addr, NULL, NULL);
> -	else
> -		ptep = find_init_mm_pte(addr, NULL);
> +	ptep = __find_linux_pte(mm->pgd, addr, NULL, &shift);
>  	local_irq_restore(flags);
> +
>  	if (!ptep || pte_special(*ptep))
>  		return ULONG_MAX;
> +
> +	if (shift > PAGE_SHIFT) {
> +		unsigned long rpnmask = (1ul << shift) - PAGE_SIZE;
> +
> +		return pte_pfn(__pte(pte_val(*ptep) | (addr & rpnmask)));
> +	}
> +
>  	return pte_pfn(*ptep);
>  }
>  
> @@ -344,7 +350,7 @@ static const struct mce_derror_table mce_p9_derror_table[] = {
>    MCE_INITIATOR_CPU,   MCE_SEV_SEVERE, true },
>  { 0, false, 0, 0, 0, 0, 0 } };
>  
> -static int mce_find_instr_ea_and_pfn(struct pt_regs *regs, uint64_t *addr,
> +static int mce_find_instr_ea_and_phys(struct pt_regs *regs, uint64_t *addr,
>  					uint64_t *phys_addr)
>  {
>  	/*
> @@ -541,7 +547,8 @@ static int mce_handle_derror(struct pt_regs *regs,
>  			 * kernel/exception-64s.h
>  			 */
>  			if (get_paca()->in_mce < MAX_MCE_DEPTH)
> -				mce_find_instr_ea_and_pfn(regs, addr, phys_addr);
> +				mce_find_instr_ea_and_phys(regs, addr,
> +							   phys_addr);
>  		}
>  		found = 1;
>  	}
>

Patch
diff mbox series

diff --git a/arch/powerpc/kernel/mce_power.c b/arch/powerpc/kernel/mce_power.c
index a814d2dfb5b0..714a98e0927f 100644
--- a/arch/powerpc/kernel/mce_power.c
+++ b/arch/powerpc/kernel/mce_power.c
@@ -26,6 +26,7 @@ 
 unsigned long addr_to_pfn(struct pt_regs *regs, unsigned long addr)
 {
 	pte_t *ptep;
+	unsigned int shift;
 	unsigned long flags;
 	struct mm_struct *mm;
 
@@ -35,13 +36,18 @@  unsigned long addr_to_pfn(struct pt_regs *regs, unsigned long addr)
 		mm = &init_mm;
 
 	local_irq_save(flags);
-	if (mm == current->mm)
-		ptep = find_current_mm_pte(mm->pgd, addr, NULL, NULL);
-	else
-		ptep = find_init_mm_pte(addr, NULL);
+	ptep = __find_linux_pte(mm->pgd, addr, NULL, &shift);
 	local_irq_restore(flags);
+
 	if (!ptep || pte_special(*ptep))
 		return ULONG_MAX;
+
+	if (shift > PAGE_SHIFT) {
+		unsigned long rpnmask = (1ul << shift) - PAGE_SIZE;
+
+		return pte_pfn(__pte(pte_val(*ptep) | (addr & rpnmask)));
+	}
+
 	return pte_pfn(*ptep);
 }
 
@@ -344,7 +350,7 @@  static const struct mce_derror_table mce_p9_derror_table[] = {
   MCE_INITIATOR_CPU,   MCE_SEV_SEVERE, true },
 { 0, false, 0, 0, 0, 0, 0 } };
 
-static int mce_find_instr_ea_and_pfn(struct pt_regs *regs, uint64_t *addr,
+static int mce_find_instr_ea_and_phys(struct pt_regs *regs, uint64_t *addr,
 					uint64_t *phys_addr)
 {
 	/*
@@ -541,7 +547,8 @@  static int mce_handle_derror(struct pt_regs *regs,
 			 * kernel/exception-64s.h
 			 */
 			if (get_paca()->in_mce < MAX_MCE_DEPTH)
-				mce_find_instr_ea_and_pfn(regs, addr, phys_addr);
+				mce_find_instr_ea_and_phys(regs, addr,
+							   phys_addr);
 		}
 		found = 1;
 	}